Ответ 1
Примечание. Существует версия этого с правильной математической установкой в 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]
[λ μ τ ]
Эта матрица отобразит (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
отображает из базисных векторов в позиции назначения, поэтому обратная матрица отображает в обратном направлении.
Шаг 5: Вычислить в сочетании Матрица C = A∙B⁻¹
.
B⁻¹
отображает из мест назначения в базовые векторы, а A
отображает оттуда исходные позиции. Таким образом, комбинация отображает позиции назначения в исходные позиции.
Шаг 6: Для каждого пикселя (x,y)
целевого изображения вычислите продукт
[x'] [x]
[y'] = C∙[y]
[z'] [1]
Это однородные координаты вашей преобразованной точки.
Шаг 7: Вычислить позицию в исходном изображении следующим образом:
sx = x'/z'
sy = y'/z'
Это называется дегомогенезацией вектора координат.
Вся эта математика будет намного проще читать и писать, если SO будет поддерживать MathJax... ☹
Выбор размера изображения
Вышеприведенное aproach предполагает, что вы знаете расположение ваших углов в целевом изображении. Для этого вам нужно знать ширину и высоту этого изображения, которое также помечено вопросительными знаками в коде. Поэтому допустим, что height
вашего выходного изображения было 1
, а width
- sourceaspect
. В этом случае общая площадь будет sourceaspect
. Вы должны масштабировать эту область в pixelcount/sourceaspect
, чтобы достичь области pixelcount
. Это означает, что вам нужно масштабировать каждую длину края на квадратный корень этого фактора. Итак, в конце концов, вы
pixelcount = 1000000.*megapixelcount;
width = round(sqrt(pixelcount*sourceaspect));
height = round(sqrt(pixelcount/sourceaspect));