Искажение изображения с помощью преобразования перспективы

StackOverflow https://stackoverflow.com/questions/2446494

Вопрос

Я пытаюсь выполнить перекос на изображении, как показано здесь


(источник: microsoft.com)
.

У меня есть массив пикселей, представляющих мое изображение, и я не уверен, что с ними делать.

Это было полезно?

Решение

Гораздо лучший способ сделать это - с помощью обратное отображение.

По сути, вы хотите "исказить" изображение, не так ли?Это означает, что каждый пиксель исходного изображения переходит в предопределенную точку - предопределение представляет собой матрицу преобразования, которая сообщает вам, как поворачивать, масштабировать, переводить, сдвигать и т.д.изображение, которое, по существу, принимает некоторую координату (x,y) на вашем изображении и говорю, что "Хорошо, новая позиция для этого пикселя (f(x),g(y)).

Это, по сути, то, что делает "деформация".

Теперь подумайте о масштабировании изображения ...скажем, в десять раз больше.Таким образом, это означает, что пиксель в (1,1) становится пикселем в (10,10) - а затем следующий пиксель, (1,2) становится пикселем (10,20) в новом образе.Но если вы будете продолжать делать это, у вас не будет значений для пикселя, (13,13) потому что, (1.3,1.3) не определено в вашем исходном изображении, и у вас будет куча отверстий в вашем новом изображении - вам придется выполнить интерполяцию для этого значения, используя четыре пикселя вокруг него в новом изображении, т. е. (10,10) , (10,20), (20,10), (200,2) - это называется билинейная интерполяция.

Но вот еще одна проблема, предположим, что ваше преобразование не было простым масштабированием и было аффинным (как образец изображения, который вы опубликовали) - тогда (1,1) стало бы чем-то вроде (2.34,4.21) и тогда вам пришлось бы округлить их в выходном изображении до (2,4) и тогда вам пришлось бы выполнить билинейную интерполяцию на новом изображении, чтобы заполнить пробелы, или более сложную интерполяцию - грязно, не так ли?

Теперь, есть ни за что чтобы отказаться от интерполяции, но нам может сойти с рук выполнение билинейной интерполяции, просто однажды.Каким образом?Простой, обратное отображение.

Вместо того чтобы рассматривать это как исходное изображение, переходящее к новому изображению, подумайте о том, откуда в исходном изображении будут взяты данные для нового изображения!Итак, (1,1) в новом изображении будет получено некоторое обратное отображение в исходном изображении, скажем, (3.4, 2.1) а затем выполните билинейную интерполяцию на исходном изображении, чтобы вычислить соответствующее значение!

Матрица преобразования

Хорошо, итак, как вы определяете матрицу преобразования для аффинного преобразования? Этот веб-сайт рассказывает вам, как это сделать, составляя различные матрицы преобразования для вращения, сдвига и т.д.

Преобразования:

alt text

Композитинг:

alt text

Окончательная матрица может быть получена путем компоновки каждой матрицы в указанном порядке, и вы инвертировать это, чтобы получить обратное отображение - используйте это, вычисляя положения пикселей в исходном изображении и интерполируя.

Другие советы

Если вам не хочется заново изобретать колесо, загляните в библиотеку OpenCV.Он реализует множество полезных функций обработки изображений, включая перспективные преобразования.Ознакомьтесь с Перспективный вариант cvWarpPerspective который я использовал для выполнения этой задачи довольно легко.

Как прокомментировал KennyTM, вам просто нужно аффинное преобразование, которое представляет собой линейное отображение, полученное путем умножения каждого пикселя на матрицу M и добавление результата к вектору перевода V.Это простая математика

end_pixel_position = M*start_pixel_position + V

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

Например, если вы хотите повернуть изображение, вы можете задать матрицу поворота следующим образом:

    | cos(a) -sin(a) |
M = |                |
    | sin(a)  cos(a) |

где a это угол, на который вы хотите повернуть свое изображение.

При масштабировании используется матрица вида:

    | s1   0 |
M = |        |
    | 0   s2 |

где s1 и s2 являются масштабирующими коэффициентами по обеим осям.

Для перевода у вас просто есть вектор V:

    | t1 |
V = |    |
    | t2 |

это добавляет t1 и t2 в пиксельные координаты.

Затем вы объединяете матрицы в одно преобразование, например, если у вас есть масштабирование, поворот и перевод, в итоге вы получите что-то вроде:

| x2 |             | x1 |
|    | = M1 * M2 * |    | + T
| y2 |             | y1 |

где:

  • x1 и y1 являются координатами пикселей перед применением преобразования,
  • x2 и y2 являются пикселями после преобразования,
  • M1 и M2 используются ли матрицы для масштабирования и поворота (ЗАПОМНИ: композиция матриц не является коммутативной!Обычно M1 * M2 * Vect != M2 * M1 * Vect),
  • T это вектор перевода, используемый для перевода каждого пикселя.
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top