Перерисовать изображение с 3D-перспективы до 2d

Мне нужно обратное преобразование перспективы, написанное на Паскале / Дельфи / Лазаре. См. Следующий рисунок:

процесс изображения

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

function redraw_3d_to_2d(sourcebitmap:tbitmap, sourceaspect:extended, point_a, point_b, point_c, point_d:tpoint, megapixelcount:integer):tbitmap; var destinationbitmap:tbitmap; x,y,sx,sy:integer; begin destinationbitmap:=tbitmap.create; destinationbitmap.width=megapixelcount*sourceaspect*???; // I dont how to calculate this destinationbitmap.height=megapixelcount*sourceaspect*???; // I dont how to calculate this for x:=0 to destinationbitmap.width-1 do for y:=0 to destinationbitmap.height-1 do begin sx:=??; sy:=??; destinationbitmap.canvas.pixels[x,y]=sourcebitmap.canvas.pixels[sx,sy]; end; result:=destinationbitmap; end; 

Мне нужна настоящая формула … Поэтому решение OpenGL не было бы идеальным …

Примечание. Существует версия этого с правильной математической установкой на Math SE.

Вычисление проективного преобразования

Перспектива – это частный случай проективного преобразования , который, в свою очередь, определяется четырьмя точками.

Шаг 1. Начиная с 4 позиций исходного изображения, названного (x1,y1) (x4,y4) , вы решаете следующую систему линейных уравнений :

 [x1 x2 x3] [λ] [x4] [y1 y2 y3]∙[μ] = [y4] [ 1 1 1] [τ] [ 1] 

Колонки образуют однородные координаты : один размер больше, созданный добавлением 1 в качестве последней записи. В последующих шагах кратность этих векторов будет использоваться для обозначения одних и тех же точек. См. Последний шаг для примера того, как вернуть их обратно в двумерные координаты.

Шаг 2. Масштабируйте столбцы с помощью только что вычисленных коэффициентов:

  [λ∙x1 μ∙x2 τ∙x3] A = [λ∙y1 μ∙y2 τ∙y3] [λ μ τ ] 

Эта matrix будет отображать (1,0,0) в кратность (x1,y1,1) , (0,1,0) кратным (x2,y2,1) , (0,0,1) до кратное (x3,y3,1) и (1,1,1)(x4,y4,1) . Таким образом, он будет отображать эти четыре специальных вектора (называемые базисными векторами в последующих объяснениях) в указанные позиции на изображении.

Шаг 3: Повторите шаги 1 и 2 для соответствующих позиций на целевом изображении, чтобы получить вторую матрицу под названием B

Это карта от базисных векторов к местам назначения.

Шаг 4: Инвертировать B для получения B⁻¹ .

B отображает из базисных векторов в позиции назначения, поэтому обратная matrix отображает в обратном направлении.

Шаг 5: Вычислите объединенную матрицу C = A∙B⁻¹ .

B⁻¹ отображает с позиций назначения на B⁻¹ векторы, тогда как A отображает оттуда в исходные позиции. Таким образом, комбинация отображает позиции назначения в исходные позиции.

Шаг 6: для каждого пикселя (x,y) целевого изображения вычислите продукт

 [x'] [x] [y'] = C∙[y] [z'] [1] 

Это однородные координаты вашей трансформированной точки.

Шаг 7. Вычислите позицию в исходном изображении следующим образом:

 sx = x'/z' sy = y'/z' 

Это называется дегомолизацией вектора координат.

Вся эта математика была бы намного легче читать и писать, если бы SO поддерживала MathJax …

Выбор размера изображения

Вышеприведенное aproach предполагает, что вы знаете расположение ваших углов в целевом изображении. Для этого вам нужно знать ширину и высоту этого изображения, которое также помечено вопросительными знаками в коде. Итак, допустим, height вашего выходного изображения sourceaspect 1 , а width была sourceaspect . В этом случае общая площадь также будет sourceaspect . Вы должны масштабировать эту область с коэффициентом pixelcount/sourceaspect для достижения области pixelcount . Это означает, что вам нужно масштабировать каждую длину края на квадратный корень этого фактора. Поэтому, в конце концов, у вас есть

 pixelcount = 1000000.*megapixelcount; width = round(sqrt(pixelcount*sourceaspect)); height = round(sqrt(pixelcount/sourceaspect)); 

Используйте Graphics32 , в частности TProjectiveTransformation (для использования с методом Transform ). Не забудьте оставить прозрачный край в исходном изображении, чтобы не получить зубчатые края.

  • Что такое быстрый математический анализатор C или Objective-C?
  • Сделать сферу с эквидистантными вершинами
  • C # decimal взять потолок 2
  • Как использовать NSDecimalNumber?
  • К власти в C?
  • Как я могу генерировать поистине (а не псевдо) случайные числа с помощью C #?
  • Что делать с высокой эффективностью Java BigDecimal?
  • Существует ли стандартная функция знака (signum, sgn) в C / C ++?
  • Обратный алгоритм Фибоначчи?
  • Использование M_PI со стандартом C89
  • Как проверить, является ли число мощностью 2
  • Давайте будем гением компьютера.