Я хотел бы предоставить небольшую предысторию, прежде чем углубляться в тему, чтобы предложить лучшее понимание. Во время летней стажировки я столкнулся с тривиальной, но сложной задачей. Я работаю с изображениями, метки которых представляют собой координаты 4 точек, ограничивающих многоугольник (псевдопрямоугольник) в данном изображении {(x₁,y₁), (x ₂,y₂), (x₃,y₃), (x₄, г₄)}.

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

Моя модель машинного обучения является кульминацией двух подмоделей. Первая подмодель отвечает за прогнозирование координат и угла (необходимых для преобразования псевдопрямоугольника в вертикальное положение). Впоследствии вторая модель обрабатывает повернутые, вертикальные, измененные по размеру и обрезанные изображения для лучшего распознавания текста. Это означает, что в какой-то момент я должен повернуть эти изображения, чтобы передать вторую модель. Но с помощью библиотеки PIL или библиотеки OpenCV это простая задача, так что же в этом сложного? И ответ: Примените тот же поворот к меткам!

Вращение как линейное преобразование в линейной алгебре

При работе с вращением линейная алгебра предлагает простой и мощный подход, поскольку каждое линейное преобразование может быть представлено матрицей. В нашем случае изображение можно рассматривать как подмножество IR², а преобразование поворота можно описать матрицей, обозначенной как T в форме (2, 2). Определить эту матрицу относительно просто — мы извлекаем координаты единичных векторов после применения поворота.

î = (cos(θ), sin(θ))и ĵ = (-sin(θ), cos(θ))Следовательно, матрица T:

Преобразование любого вектора XIR² s.t. Х= х . î+ y . ĵпредставляется умножением матрицы на вектор : rot(X) = T.X
Однако, применяя эту теорию к задаче, мы имеем напрямую невозможно, и вот почему !

Представление изображения: немного фона

Математическая ссылка обычно описывает декартову систему координат с началом, расположенным в точке O(0,0), где ось X направлена ​​вправо, а ось Y направлена ​​вверх. Однако при работе с изображением используется другое соглашение. В этом случае начало оси X находится в нижнем левом углу изображения, простираясь к вправо, а начало оси Y находится в верхнем левом углу изображения, простираясь вниз .

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

Волшебные модификации и без того волшебной математической формулы

После целого дня изучения различных источников в Google и использования нескольких фрагментов кода из StackOverflow, MATLAB и chatGPT я постоянно награждался своеобразным набором координат, которые не имели никакого сходства с конкретной областью на изображении. Прорыв произошел, когда я понял, что выделение точек и работа с ними в математическом эталоне позволит мне точно выполнять необходимые операции, прежде чем преобразовать их обратно в эталон изображения. Итак, давайте разобьем процесс ротации на крошечные, управляемые шаги.

определение переменных:

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

path = "/..."
img = Image.open(path)
height, width = img.height, img.width
label = np.array([136,745,782,1456,722,1504,76,796]).reshape(4,2)
angle = 48
T = np.array([[np.cos(angle), -np.sin(angle)],
              [np.sin(angle),  np.cos(angle)]])

#Visualize the label using image representation
plt.imshow(img)
plt.scatter(labels[:,0], labels[:,1], c='r', s=8)
plt.show()

#Visualize the label using mathematical representation
plt.scatter(labels[:,0], labels[:,1], c='r', s=8)
plt.xlim(0, width)
plt.ylim(0, height)
plt.show()

Представить точку в математическом справочнике

Первое, что нужно сделать, это сымитировать координаты, представленные на изображении в математическом справочнике:

label[:, 1] = height - label[:, 1]

#Visualize the label after adjusting height
plt.scatter(label[:,0], label[:,1], c='r', s=8)
plt.xlim(0, width)
plt.ylim(0, height)
plt.show()

Применить необходимый перевод перед ротацией

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

center = np.array([width//2, height//2])
label = label - center

#Visualize the label after placing reference's origin on image center
plt.scatter(label[:,0], label[:,1], c='r', s=8)
plt.xlim(-width//2, width//2)
plt.ylim(-height//2, height//2)
plt.show()

Готов применять сложную линейную алгебру

Теперь, когда координаты точно определены, мы готовы выполнить поворот с помощью умножения матрицы на вектор.

angle_rad = angle * np.pi / 180
T = np.array([[np.cos(pangle_rad), -np.sin(pangle_rad)], \
                [np.sin(pangle_rad), np.cos(pangle_rad)]])
label = ([email protected]).T

#Visualize the rotated coordinates
plt.scatter(label[:,0], label[:,1], c='r', s=8)
plt.xlim(-width//2, width//2)
plt.ylim(-height//2, height//2)
plt.show()

Отменить некоторые изменения

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

label = plabel + center
label[:, 1] = height - label[:, 1]

Наконец, поверните изображение и визуализируйте результат

Теперь, когда вращение метки выполнено, последний шаг — повернуть все изображение, чтобы выровнять его с вновь преобразованными координатами. Визуализация повернутого изображения и соответствующей метки позволит нам убедиться в успешности нашего процесса вращения. Стоит отметить, что для нашей конкретной задачи потеря некоторых данных из-за ротации не является проблемой.

img = img.rotate(angle)

#Visualize image and corresponding label after rotation
plt.imshow(img)
plt.scatter(label[:,0], label[:,1], c='r', s=8)
plt.show()

Бонус:

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

bias = np.array([(new_size[0] - width) // 2, (new_size[1] - height) // 2])
label = label + bias

Рекомендации