5.23. Корекція перспективи¶
Попередження
Довільна матриця transform 3 на 3 підтримується лише на OpenMV Cam N6 – на будь-якій іншій платі ключове слово мовчки ігнорується. Програми, яким потрібно запускатися деінде, повинні використовувати стандартний метод rotation_corr() (у формі corners=) або попередньо обчислювати виправлене зображення поза платою.
Стандартний метод rotation_corr() реалізує певну родину перспективних деформацій за допомогою невеликого набору параметрів і працює на кожній підтримуваній платі. Деяким програмам потрібна деформація, яка не вписується у цю форму: довільне проєктивне перевідображення з одного чотирикутника в інший, відкалібрована корекція для відомого кріплення, що вже була розрахована заздалегідь, матриця деформації, готова до використання від якогось попереднього алгоритму. Для таких випадків draw_image() – разом із copy(), crop() та scale() – приймає ключове слово transform, яке бере вручну побудовану матрицю 3 на 3, що безпосередньо описує деформацію.
5.23.1. Афінні та проєктивні перетворення¶
Геометричні деформації виражаються в однорідних координатах: позиція пікселя (x, y) з доданою 1, помножена на матрицю 3 на 3.
Форма афінного перетворення є відправною точкою. Його нижній рядок фіксований на \((0, 0, 1)\):
Виписавши, кожна вихідна координата є лінійною комбінацією вхідних координат плюс константа:
що охоплює масштабування, обертання, зсув і трансляцію у будь-якому поєднанні – і при всіх цих перетвореннях паралельні лінії залишаються паралельними.
Форма проєктивного (перспективного) перетворення звільняє нижній рядок:
Виписавши:
Ділення на \(w' = g x + h y + 1\) робить перетворення проєктивним, а не просто афінним. Коли \(g\) та \(h\) обидва рівні нулю, \(w'\) залишається рівним одиниці і ділення нічого не змінює – це знову афінна форма. Коли будь-яке з них ненульове, \(w'\) змінюється залежно від вхідної позиції і пікселі в різних позиціях отримують різний ступінь перспективного стиснення, що вже не зберігає паралельності прямих ліній – це і є ефект трапецієподібного спотворення при погляді на плоску поверхню під косим кутом. Проєктивне перетворення є найбільш загальним геометричним викривленням, що переводить прямі лінії у прямі лінії; масштабування, відзеркалення, транспонування, обертання та корекція чотирьох кутів – усе це окремі випадки одного перетворення.
Іменовані перетворення безпосередньо випливають з афінної форми. Тотожне перетворення – це одинична матриця, а:
Для більшості вручну побудованих перетворень програма починає з однієї з цих матриць як основи і множить на подальші матриці для кожної додаткової операції, завершуючи єдиною матрицею 3 на 3, що описує складену деформацію. Матриці застосовуються справа наліво: \(M = T R S\) спочатку виконує масштабування, потім обертання, а потім трансляцію. Складена матриця, яка потрібна в кінцевому підсумку всім, – це обертання навколо центру зображення: проста матриця обертання обертає зображення навколо початку координат пікселів у верхньому лівому куті, тому відцентрована версія переміщує центр \((c_x, c_y)\) до початку координат, виконує обертання і переміщує назад:
5.23.2. Ключове слово transform¶
Матриця передається через ключове слово transform, що задається як масив ulab.numpy.ndarray розміром 3 на 3. Метод, який слід використовувати, – draw_image(), що деформує джерело через матрицю під час малювання на цільове зображення – результат потрапляє до буфера, яким керує програма, а деформація поєднується з усім іншим у виклику: масштабуванням, альфа-змішуванням, маскуванням.
import ulab.numpy as np
M = np.array([[1.2, 0.0, -20.0],
[0.0, 1.2, -15.0],
[0.0, 0.0, 1.0]])
canvas.draw_image(img, transform=M)
Приклад деформує img на canvas з масштабуванням 1.2 у кожному напрямку та зсувом ліворуч і вгору на 20 та 15 пікселів відповідно – афінна деформація, побудована безпосередньо з елементів матриці, описаних вище. Те саме ключове слово для copy(), crop() та scale() застосовує деформацію до самого зображення.