Обрезка изображения с использованием перспективных преобразований

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


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

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

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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