Как я могу применить регистрацию изображений к изображениям и их аннотациям с помощью opencv?

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

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, как я могу применить матрицу гомографии?

Вам придется делать это по пунктам. Преобразуйте ограничивающую рамку в координаты верхнего левого и нижнего правого угла. x0,y0 — вверху слева. Итак, нижний правый угол — это x0+ширина,y0+высота. Затем переформатируйте, добавив третью координату 1, как (x,y,1). Затем спроецируйте эти точки с помощью матрицы гомографии (умножение матрицы). Затем преобразуйте x1,y1 обратно в ширину и высоту. Ширина = x1-x0, Высота = y1-y0, чтобы снова сформировать ограничивающую рамку, если это необходимо. Если это не сработает, возможно, вам придется сначала инвертировать матрицу гомографии. Я не могу вспомнить, прямое или обратное преобразование.

fmw42 14.03.2024 18:43
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
222
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Полигоны

Учитывая любой многоугольник, пропустите его через 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)

Ivan 15.03.2024 12:02

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

Christoph Rackwitz 15.03.2024 12:15

Другие вопросы по теме