Наклон изображения с использованием перспективных преобразований - PullRequest
10 голосов
/ 15 марта 2010

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


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

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

Ответы [ 3 ]

53 голосов
/ 15 марта 2010

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

По сути, вы хотите "деформировать" изображение, верно? Это означает, что каждый пиксель в исходном изображении переходит в предопределенную точку - предопределением является матрица преобразования, которая говорит вам, как вращать, масштабировать, переводить, сдвигать и т. Д. Изображение, которое по существу принимает некоторую координату (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

Compositing:

alt text

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

3 голосов
/ 15 марта 2010

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

2 голосов
/ 15 марта 2010

Как прокомментировал 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 - вектор перевода, используемый для перевода каждого пикселя.
...