Координаты в искаженной сетке - PullRequest
4 голосов
/ 31 мая 2010

У меня есть сетка в 2D-системе, подобной той, что была на предыдущем изображении, где даны все точки A, B, C, D, A ', B', C ', D' (то есть я знаю соответствующий x- и y-координаты).

Мне нужно вычислить x- и y-координаты A (новый), B (новый), C (новый) и D (новый), когда сетка искажена (так что A 'перемещается в A' ( новый), B 'перемещается в B' (новый), C 'перемещается в C' (новый) и D 'перемещается в D' (новый)).

Искажение происходит таким образом, что каждая из линий сетки делится на подстроки равной длины (например, это означает, что AB делится на 5 частей равной длины | AB | / 5 и A (new ) B (новый) делится на 5 частей равной длины | A (новый) B (новый) | / 5).

Искажение выполняется с помощью класса DistortImage движка Sandy 3D Flash . (Моя практическая задача - исказить изображение, используя этот класс, где маркеры расположены не по углам изображения , как в этом демо , а где-то внутри него).

альтернативный текст http://www.gefragt.de/distorted_grid.png

Ответы [ 7 ]

3 голосов
/ 21 июня 2010

Я не могу дать вам полный ответ, но я почти уверен, что вы найдете его в «Основах наложения текстур и деформации изображения» Пола С. Хекберта: http://www.cs.cmu.edu/~ph/texfund/texfund.pdf (в приложении он содержит исходный код для всех видов отображений)

2 голосов
/ 10 июня 2010

Для меня это выглядит как линейное преобразование. Мы знаем это, потому что любая линия в исходном графе также является линией в преобразованном графе (это не всегда верно для демонстрации, которую вы дали, но будет верно, если вы будете следовать указаниям, которые вы дали в своем вопросе, и не допустите вогнутые вершины) , Я верю, что AS3 имеет встроенную поддержку для манипуляций с матрицами преобразования. Если нет, вы можете реализовать их самостоятельно.

[ x' ]  =   [ a b ] x [ x ]
[ y' ]      [ c d ]   [ y ]

Это матрицы. Первый - это вектор (ваша конечная точка), который равен определенной матрице 2x2, умноженной на вектор (ваша исходная точка)

Если вы не знакомы с умножением матриц, это можно упростить до:

x' = a*x + b*y
y' = c*x + b*y

Любое линейное преобразование может быть представлено этой матрицей два на два a, b, c и d. Выберите числа для каждого из них, и вы получите линейное преобразование. Итак, как найти значения a, b, c и d, которые дадут вам ваши?

Для четырех неизвестных вам нужно четыре уравнения. Если вы посмотрите на уравнения выше, вы увидите, что одна точка («вектор») и ее преобразование даст вам два уравнения. Итак ... нам нужны две точки. Как вы увидите позже, будет полезно выбрать точки в нетрансформированной форме (m, 0) и (0, n) (т. Е. Одна вдоль оси x, а другая вдоль оси y).

В вашем примере это легко найти! Это B и D (если A или C ваше происхождение)!

Я буду использовать несколько другое обозначение: «простые числа» для преобразованных версий точек.

B => B'
B_x => B'_x
B_y => B'_y

Если вам известны координаты B и D до и после, вы можете найти матрицу преобразования a, b, c, d.

Настройка ваших уравнений:

B'_x = a * B_x + b * B_y
B'_y = c * B_x + d * B_y

D'_x = a * D_x + b * D_y
D'_y = c * D_x + d * D_y

Теперь предположим, что B - это ваша точка на оси x в форме (B_x, 0). Скажите, что D - ваша точка оси Y в форме (0, D_y). Если это наоборот, переключите их. Здесь мы предполагаем, что ваш источник A = (0,0), как в большинстве приложений Flash.

Установив B_y = 0 и D_x = 0, получим:

B'_x = a * B_x + b * 0
B'_y = c * B_x + d * 0
D'_x = a * 0   + b * D_y
D'_y = c * 0   + d * D_y

Используя силы алгебры, мы находим:

a = B'_x / B_x
c = B'_y / B_x
b = D'_x / D_y
d = D'_y / D_y

Итак, вкратце:

Если вам известны исходные точки: (вершины исходной оси x и y)

M = (M_x, 0)
N = (0  , N_x)

и их преобразованные / искаженные точки

M' = (M'_x, M'_y)
N' = (N'_x, N'_y)

(так что M => M 'и N => N')

Затем рассчитайте и сохраните эти четыре переменные:

a = M'_x / M_x
b = N'_x / N_y
c = M'_y / M_x
d = N'_y / N_y

и наконец:

(x, y)  =>  ( a*x + b*y , c*x + d*y )

edit: Хорошо, я пробежал несколько ваших преобразований произвольных углов и понял, что сделал поспешные выводы, когда предположил, что ваше преобразование было линейным. Приведенные выше уравнения будут линейными только при двух условиях:

  1. Ваша новая сетка имеет форму некоторого повернутого параллелограмма (а у вас оригинальная квадратная, "нормальная" сетка)
  2. Положение вашей (0,0) исходной точки не меняется.

Теперь я не уверен, с какими степенями свободы вы позволяете позиционировать свои ручки, но, возможно, вы можете ограничить их так, чтобы ваше сеточное пространство всегда имело форму повернутого параллелограмма.

1 голос
/ 25 июня 2010

Пусть (u, v) представляют координаты "текстуры".Ваши маркеры остаются с одинаковыми координатами текстуры независимо от искажений сетки.

Таким образом, в пространстве текстур A = (0,0) B = (1,0) C = (1,1) D = (0, 1) A '= (au, av) B' = (bu, bv) ...

Мы можем преобразовать текстурное пространство в пиксельное пространство.

P (u, v)= A * (1-u) (1-v) + B u * (1-v) + C u v + D * (1-u) * v

(u, v - координаты текстуры, а A, B, C, D - координаты пикселей)

Итак, если ваш дескриптор A 'определен как координата текстуры (.35, .15), то положение A 'в пиксельном пространстве определяется как P (.35, .15).

Теперь, скажем, пользователь перетаскивает ручку A '.Нам нужно решить, для нового местоположения А. B, C, D остаются неизменными.Это просто алгебра.

A' = A*(1-au)*(1-av) + B*au*(1-av) + C*au*av + D*(1-au)*av
A' - B*au*(1-av) - C*au*av - D*(1-au)*av = A*(1-au)*(1-av)
A = (A' - B*au*(1-av) - C*au*av - D*(1-au)*av) / ((1-au)*(1-av))

Не так уж плохо.Тот же процесс получает формулы для других дескрипторов.Вот мой код C #.Он вызывается, когда перетаскивается любое из 8 «больших пальцев»:

     double au = .35, av = .15; // texture coordinates of A'
     double bu = .8, bv = .2;   // texture coordinates of B'
     double cu = .8, cv = .6;   // texture coordinates of C'
     double du = .2, dv = .9;   // texture coordinates of D'

     // if we're dragging A' (AA), then move A, etc.
     if (sender == ThumbAA) A = (AA - B*au*(1-av) - C*au*av - D*(1-au)*av) / ((1-au)*(1-av));
     if (sender == ThumbBB) B = (BB - A*(1-bu)*(1-bv) - C*bu*bv - D*(1-bu)*bv) / (bu*(1-bv));
     if (sender == ThumbCC) C = (CC - A*(1-cu)*(1-cv) - B*cu*(1-cv) - D*(1-cu)*cv) / (cu*cv);
     if (sender == ThumbDD) D = (DD - A*(1-du)*(1-dv) - B*du*(1-dv) - C*du*dv) / ((1-du)*dv);

     // update position of A', B', C', D'   
     AA = A*(1-au)*(1-av) + B*au*(1-av) + C*au*av + D*(1-au)*av;
     BB = A*(1-bu)*(1-bv) + B*bu*(1-bv) + C*bu*bv + D*(1-bu)*bv;
     CC = A*(1-cu)*(1-cv) + B*cu*(1-cv) + C*cu*cv + D*(1-cu)*cv;
     DD = A*(1-du)*(1-dv) + B*du*(1-dv) + C*du*dv + D*(1-du)*dv;

видео моего демонстрационного приложения: http://screencast.com/t/NDU2ZWRj

Это не дает точного ответа на вопрос о перемещении 4-х ручекв то же время.Это то, что вы действительно хотите?Кроме того, дайте мне знать, если координаты текстуры ваших ручек не определены заранее.Вы можете конвертировать пиксельные координаты в текстуру, но это сложнее.

0 голосов
/ 26 июня 2010

Вы говорите о 2D-системе, но применяемое искажение - это 3D-искажение (хотя и проецируется обратно в 2d, конечно) - это преднамеренно?

В общем, я на самом деле не уверен, что возможно вычислить новое местоположение A'new без большей информации об использовании перспективной проекции, чем просто новые местоположения ABCD. В конце концов, перспективная проекция преувеличивает близлежащие расстояния и сжимает отдаленные - и степень, в которой это происходит, зависит от расстояния от фокальной точки (что эквивалентно FOV).

В любом случае было бы проще повторно использовать все, что нужно для вычисления проекции, в первую очередь - если вы можете получить исходную матрицу преобразования и перспективное преобразование, вы можете напрямую применить их к A 'B' и D '.

0 голосов
/ 31 мая 2010

Возможно, вы могли бы что-то выяснить, но я сомневаюсь, что вам или вашим пользователям понравится результат.

Чтобы понять, почему, выберите точку внутри изображения.Скажем, вы хотите немного сдвинуть его вверх.Вы можете сделать это, переместив любой из четырех углов (попробуйте в демоверсии).Это означает, что если вы хотите поставить ручку туда и переместить ее вверх, четыре угла будут двигаться в некоторой комбинации.Скорее всего, углы не будут делать то, что вы хотите.Например, все четыре из них могут продвинуться на одну и ту же величину, что приведет к чистому переводу и отсутствию перекоса.Или один угол может двигаться, но, возможно, не тот, который вы ожидали.Существует бесконечное количество решений, и, скорее всего, вы выбираете не то, которое ожидаете вы (или кто-то еще).

Кстати, метод искажения, используемый в демо, - это "билинейная интерполяция"».Наличие ручек по углам, вероятно, лучший способ управлять им.

0 голосов
/ 31 мая 2010

Вам нужна помощь с алгоритмической точки зрения (трансформации и т. Д.) Или вам нужна помощь по достижению трансформаций, в частности, с помощью 3D-движка Sandy?

0 голосов
/ 31 мая 2010

Вы уверены, что хотите заняться всем этим за ручки? в примерах маркеры служат в качестве опорных точек на мувиклипе для рисования, они никак не связаны с изображением или искажениями на нем. если вы хотите, чтобы в изображении были только обработчики, вам просто нужно сместить значение вычисления точки (например, topRightCorner = new Point(pointb.x +10, point.y - 10))

Если вы действительно хотите перейти к вычислению точных баллов, тогда вы можете попробовать вызвать localToGlobal(new Point(this.x, this.y)) из обработчика, чтобы выяснить, где он находится (и, следовательно, перевод, который к нему применен). в противном случае вам придется иметь дело с матрицами преобразования и точно определить, как класс вычисляет свои треугольники.

для очень хорошего руководства по матрицам преобразования, смотрите здесь: senoular.com

удачи

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...