Я хочу распространить метки многоугольников из исходного изображения в целевое. Целевое изображение — это просто исходное изображение, но слегка переведенное. Я нашел этот фрагмент кода, который позволяет мне зарегистрировать исходное изображение в целевом изображении. Если вы напишите это как функцию, это будет выглядеть так:
import numpy as np
import cv2
def register_images(
align: np.ndarray,
reference: np.ndarray,
):
"""
Registers two RGB images with each other.
Args:
align: Image to be aligned.
reference: Reference image to be used for alignment.
Returns:
Registered image and transformation matrix.
"""
# Convert to grayscale if needed
_align = align.copy()
_reference = reference.copy()
if _align.shape[-1] == 3:
_align = cv2.cvtColor(_align, cv2.COLOR_RGB2GRAY)
if _reference.shape[-1] == 3:
_reference = cv2.cvtColor(_reference, cv2.COLOR_RGB2GRAY)
height, width = _reference.shape
# Create ORB detector with 5000 features
orb_detector = cv2.ORB_create(500)
# Find the keypoint and descriptors
# The first arg is the image, second arg is the mask (not required in this case).
kp1, d1 = orb_detector.detectAndCompute(_align, None)
kp2, d2 = orb_detector.detectAndCompute(_reference, None)
# Match features between the two images
# We create a Brute Force matcher with Hamming distance as measurement mode.
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# Match the two sets of descriptors
matches = list(matcher.match(d1, d2))
# Sort matches on the basis of their Hamming distance and select the top 90 % matches forward
matches.sort(key=lambda x: x.distance)
matches = matches[:int(len(matches) * 0.9)]
no_of_matches = len(matches)
# Define empty matrices of shape no_of_matches * 2
p1 = np.zeros((no_of_matches, 2))
p2 = np.zeros((no_of_matches, 2))
for i in range(len(matches)):
p1[i, :] = kp1[matches[i].queryIdx].pt
p2[i, :] = kp2[matches[i].trainIdx].pt
# Find the homography matrix and use it to transform the colored image wrt the reference
homography, mask = cv2.findHomography(p1, p2, cv2.RANSAC)
transformed_img = cv2.warpPerspective(align, homography, (width, height))
return transformed_img, homography
Теперь я могу получить доступ к преобразованному изображению и матрице гомографии, используемой для выравнивания двух изображений. Чего я не понимаю, так это как применить ту же трансформацию к многоугольникам и ограничивающим рамкам, используемым для аннотирования изображения.
В частности, аннотации имеют формат COCO, что означает, что вы можете получить доступ к координатам следующим образом:
x0, y0, width, height = bounding_box
А аннотации представляют собой список координат полигона:
segmentations = [poly1, poly2, poly3, ...] # segmentations are a list of polygons
for poly in segmentations:
x_coords = poly[0::2] # x coordinates are integer values on the even index in the poly list
y_coords = poly[1::2] # y coordinates are integer values on the odd index in the poly list
Получив доступ к координатам x и y, как я могу применить матрицу гомографии?
Учитывая любой многоугольник, пропустите его через perspectiveTransform()
вместе с матрицей гомографии. Вот и все.
perspectiveTransform()
выполняет всю линейную алгебру, включая расширение точек (x,y)
до (x,y,1)
, очевидное умножение матриц, деление на добавленное измерение w
и удаление добавленного измерения.
Убедитесь, что многоугольник задан как массив NumPy. Если OpenCV решит вести себя глупо, убедитесь, что форма массива аналогична (N, 1, 2)
заданным N точкам координат (x,y). dtype
также может заставить его играть глупо. Возможно, ему понадобятся поплавки определенной ширины.
С какого бы типа коробки вы ни начали, вам придется вычислить ее угловые точки. Теперь это многоугольник. Дальше: см. выше.
Если вы преобразуете таким образом ограничивающую рамку, выровненную по оси, она, скорее всего, больше не будет выглядеть выровненной по оси из-за гомографии (перспектива, сдвиг, вращение,...). Если вам нужен прямоугольник, выровненный по оси вокруг трансформированного блока или многоугольника, вызовите boundingRect()
для набора точек.
Недостаточно трансформировать только верхний левый и нижний правый углы коробки. Если преобразование представляет собой обычное вращение (или что-то иное, кроме перемещения), и вы интерпретировали преобразованные точки как углы нового прямоугольника, выровненного по оси, этот блок будет разбит. Оно не совпадало с той частью изображения, которую описывало.
first box picture from Creativity103 on Flickr and thumbnail of second box picture from someone on getty
Гомографии OpenCV даны в прямом смысле. По пунктам с perspectiveTransform()
они работают как есть.
Вам может понадобиться, а может и не потребоваться инвертировать гомографию. Это зависит от того, как вы это рассчитали. np.linalg.inv()
сделал бы это, и, вероятно, в OpenCV тоже есть какая-то функция.
Функции warp...()
неявно инвертируют заданную им гомографию, потому что это необходимо алгоритму выборки. При наличии флага WARP_INVERSE_MAP
предполагается, что переданная гомография уже инвертирована, следовательно, не инвертируется неявно, а используется непосредственно в выборке в смысле «вытягивания».
Если матрицы необходимо инвертировать, следует инвестировать порядок изображений. Для этого варианта использования этого должно быть достаточно (нет необходимости в ref->query и qurey->ref)
конечно, но я не хотел вдаваться в это. это случайность, которую мне пришлось немного прояснить, поскольку она появилась в комментарии. ОП не дал никаких указаний на то, что с этим есть какие-либо проблемы.
Вам придется делать это по пунктам. Преобразуйте ограничивающую рамку в координаты верхнего левого и нижнего правого угла. x0,y0 — вверху слева. Итак, нижний правый угол — это x0+ширина,y0+высота. Затем переформатируйте, добавив третью координату 1, как (x,y,1). Затем спроецируйте эти точки с помощью матрицы гомографии (умножение матрицы). Затем преобразуйте x1,y1 обратно в ширину и высоту. Ширина = x1-x0, Высота = y1-y0, чтобы снова сформировать ограничивающую рамку, если это необходимо. Если это не сработает, возможно, вам придется сначала инвертировать матрицу гомографии. Я не могу вспомнить, прямое или обратное преобразование.