Как визуализировать сопоставление дескрипторов с помощью модуля opencv в python

Я пытаюсь использовать opencv с python. Я написал код соответствия дескриптора (SIFT, SURF или ORB) в C++ версии opencv 2.4. Я хочу преобразовать этот код в opencv с помощью python. Я нашел несколько документов о том, как использовать функции opencv в C++, но многие из функций opencv в python я не смог найти, как их использовать. Вот мой код Python, и моя текущая проблема заключается в том, что я не знаю, как использовать «drawMatches» opencv С++ в Python. Я нашел cv2.DRAW_MATCHES_FLAGS_DEFAULT, но понятия не имею, как его использовать. Вот мой код соответствия Python с использованием дескрипторов ORB:

im1 = cv2.imread(r'C:\boldt.jpg')
im2 = cv2.cvtColor(im1, cv2.COLOR_BGR2GRAY)
im3 = cv2.imread(r'C:\boldt_resize50.jpg')
im4 = cv2.cvtColor(im3, cv2.COLOR_BGR2GRAY)

orbDetector2 = cv2.FeatureDetector_create("ORB")
orbDescriptorExtractor2 = cv2.DescriptorExtractor_create("ORB")
orbDetector4 = cv2.FeatureDetector_create("ORB")
orbDescriptorExtractor4 = cv2.DescriptorExtractor_create("ORB")

keypoints2 = orbDetector2.detect(im2)
(keypoints2, descriptors2) = orbDescriptorExtractor2.compute(im2,keypoints2)
keypoints4 = orbDetector4.detect(im4)
(keypoints4, descriptors4) = orbDescriptorExtractor4.compute(im4,keypoints4)
matcher = cv2.DescriptorMatcher_create('BruteForce-Hamming')
raw_matches = matcher.match(descriptors2, descriptors4)
img_matches = cv2.DRAW_MATCHES_FLAGS_DEFAULT(im2, keypoints2, im4, keypoints4, raw_matches)
cv2.namedWindow("Match")
cv2.imshow( "Match", img_matches);

Сообщение об ошибке строки "img_matches = cv2.DRAW_MATCHES_FLAGS_DEFAULT(im2, keypoints2, im4, keypoints4, raw_matches)"

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'long' object is not callable

Я потратил много времени на поиск документации и примеров использования функций opencv с python. Однако я очень расстроен, потому что очень мало информации об использовании функций opencv в python. Будет очень полезно, если кто-нибудь научит меня, где я могу найти документацию о том, как использовать каждую функцию модуля opencv в python. Я ценю ваше время и помощь.


person user1433201    schedule 20.06.2012    source источник


Ответы (3)


вы можете визуализировать сопоставление функций в Python следующим образом. Обратите внимание на использование библиотеки scipy.

# matching features of two images
import cv2
import sys
import scipy as sp

if len(sys.argv) < 3:
    print 'usage: %s img1 img2' % sys.argv[0]
    sys.exit(1)

img1_path = sys.argv[1]
img2_path = sys.argv[2]

img1 = cv2.imread(img1_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)
img2 = cv2.imread(img2_path, cv2.CV_LOAD_IMAGE_GRAYSCALE)

detector = cv2.FeatureDetector_create("SURF")
descriptor = cv2.DescriptorExtractor_create("BRIEF")
matcher = cv2.DescriptorMatcher_create("BruteForce-Hamming")

# detect keypoints
kp1 = detector.detect(img1)
kp2 = detector.detect(img2)

print '#keypoints in image1: %d, image2: %d' % (len(kp1), len(kp2))

# descriptors
k1, d1 = descriptor.compute(img1, kp1)
k2, d2 = descriptor.compute(img2, kp2)

print '#keypoints in image1: %d, image2: %d' % (len(d1), len(d2))

# match the keypoints
matches = matcher.match(d1, d2)

# visualize the matches
print '#matches:', len(matches)
dist = [m.distance for m in matches]

print 'distance: min: %.3f' % min(dist)
print 'distance: mean: %.3f' % (sum(dist) / len(dist))
print 'distance: max: %.3f' % max(dist)

# threshold: half the mean
thres_dist = (sum(dist) / len(dist)) * 0.5

# keep only the reasonable matches
sel_matches = [m for m in matches if m.distance < thres_dist]

print '#selected matches:', len(sel_matches)

# #####################################
# visualization of the matches
h1, w1 = img1.shape[:2]
h2, w2 = img2.shape[:2]
view = sp.zeros((max(h1, h2), w1 + w2, 3), sp.uint8)
view[:h1, :w1, :] = img1  
view[:h2, w1:, :] = img2
view[:, :, 1] = view[:, :, 0]  
view[:, :, 2] = view[:, :, 0]

for m in sel_matches:
    # draw the keypoints
    # print m.queryIdx, m.trainIdx, m.distance
    color = tuple([sp.random.randint(0, 255) for _ in xrange(3)])
    cv2.line(view, (int(k1[m.queryIdx].pt[0]), int(k1[m.queryIdx].pt[1])) , (int(k2[m.trainIdx].pt[0] + w1), int(k2[m.trainIdx].pt[1])), color)


cv2.imshow("view", view)
cv2.waitKey()
person wall-e    schedule 28.12.2012
comment
При запуске вашего кода я получаю сообщение об ошибке в строке 66, TypeError: integer argument expected, got float - person gilbertbw; 05.01.2014
comment
@wall-e анонимный пользователь только что отредактировал ваш пост, возможно, он захочет проверить, не нарушил ли он его. - person OGHaza; 22.01.2014
comment
view[:h1, :w1, :] = img1 ValueError: не удалось транслировать входной массив из формы (322 518) в форму (322 518,3) - person Giuseppe; 13.06.2016
comment
Хорошо, проблема в том, что img не всегда 3-канальный, как указал @brainless. Это зависит от версии OpenCV. Так что в моем случае (я использую 2.7.13) мне пришлось откатиться на исходную версию, которую выложили валл-и - person Giuseppe; 14.06.2016

Я также сам написал что-то, что просто использует интерфейс OpenCV Python, и я не использовал scipy. drawMatches является частью OpenCV 3.0.0 и не является частью OpenCV 2, которую я сейчас использую. Несмотря на то, что я опаздываю на вечеринку, вот моя собственная реализация, которая максимально имитирует drawMatches.

Я предоставил свои собственные изображения, на одном из которых изображен оператор, а на другом — то же самое изображение, но повернутое на 55 градусов против часовой стрелки.

Основная предпосылка того, что я написал, заключается в том, что я выделяю выходное изображение RGB, где количество строк является максимальным из двух изображений для размещения обоих изображений в выходном изображении, а столбцы - это просто сумма обоих столбцов. вместе. Я размещаю каждое изображение в соответствующих местах, затем просматриваю цикл всех совпадающих ключевых точек. Я извлекаю ключевые точки, совпадающие между двумя изображениями, затем извлекаю их (x,y) координаты. Затем я рисую круги в каждом из обнаруженных мест, а затем рисую линию, соединяющую эти круги вместе.

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

Без дальнейших церемоний:

import numpy as np
import cv2

def drawMatches(img1, kp1, img2, kp2, matches):
    """
    My own implementation of cv2.drawMatches as OpenCV 2.4.9
    does not have this function available but it's supported in
    OpenCV 3.0.0

    This function takes in two images with their associated 
    keypoints, as well as a list of DMatch data structure (matches) 
    that contains which keypoints matched in which images.

    An image will be produced where a montage is shown with
    the first image followed by the second image beside it.

    Keypoints are delineated with circles, while lines are connected
    between matching keypoints.

    img1,img2 - Grayscale images
    kp1,kp2 - Detected list of keypoints through any of the OpenCV keypoint 
              detection algorithms
    matches - A list of matches of corresponding keypoints through any
              OpenCV keypoint matching algorithm
    """

    # Create a new output image that concatenates the two images together
    # (a.k.a) a montage
    rows1 = img1.shape[0]
    cols1 = img1.shape[1]
    rows2 = img2.shape[0]
    cols2 = img2.shape[1]

    out = np.zeros((max([rows1,rows2]),cols1+cols2,3), dtype='uint8')

    # Place the first image to the left
    out[:rows1,:cols1,:] = np.dstack([img1, img1, img1])

    # Place the next image to the right of it
    out[:rows2,cols1:cols1+cols2,:] = np.dstack([img2, img2, img2])

    # For each pair of points we have between both images
    # draw circles, then connect a line between them
    for mat in matches:

        # Get the matching keypoints for each of the images
        img1_idx = mat.queryIdx
        img2_idx = mat.trainIdx

        # x - columns
        # y - rows
        (x1,y1) = kp1[img1_idx].pt
        (x2,y2) = kp2[img2_idx].pt

        # Draw a small circle at both co-ordinates
        # radius 4
        # colour blue
        # thickness = 1
        cv2.circle(out, (int(x1),int(y1)), 4, (255, 0, 0), 1)   
        cv2.circle(out, (int(x2)+cols1,int(y2)), 4, (255, 0, 0), 1)

        # Draw a line in between the two points
        # thickness = 1
        # colour blue
        cv2.line(out, (int(x1),int(y1)), (int(x2)+cols1,int(y2)), (255, 0, 0), 1)


    # Show the image
    cv2.imshow('Matched Features', out)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

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

введите здесь описание изображения

введите здесь описание изображения

Я использовал детектор ORB OpenCV для обнаружения ключевых точек и использовал нормализованное расстояние Хэмминга в качестве меры расстояния для сходства, поскольку это двоичный дескриптор. Как таковой:

import numpy as np
import cv2

img1 = cv2.imread('cameraman.png') # Original image
img2 = cv2.imread('cameraman_rot55.png') # Rotated image

# Create ORB detector with 1000 keypoints with a scaling pyramid factor
# of 1.2
orb = cv2.ORB(1000, 1.2)

# Detect keypoints of original image
(kp1,des1) = orb.detectAndCompute(img1, None)

# Detect keypoints of rotated image
(kp2,des2) = orb.detectAndCompute(img2, None)

# Create matcher
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Do matching
matches = bf.match(des1,des2)

# Sort the matches based on distance.  Least distance
# is better
matches = sorted(matches, key=lambda val: val.distance)

# Show only the top 10 matches
drawMatches(img1, kp1, img2, kp2, matches[:10])

Это изображение, которое я получаю:

введите здесь описание изображения

person rayryeng    schedule 07.10.2014
comment
Привет @rayryeng Когда я пытаюсь запустить приведенный выше код, я получаю Traceback (последний последний вызов): файл orb1.py, строка 33, в ‹module› out[:rows1,:cols1,:] = np.dstack( [img1, img1, img1]) ValueError: не удалось транслировать входной массив из формы (900,1440,9) в форму (900,1440,3) - person Bhushan; 12.08.2015
comment
@BhushanPatil - внимательно прочитайте строку документации функции. Требуются изображения в градациях серого. Вы используете изображения RGB. Вам необходимо преобразовать изображения в оттенки серого, прежде чем использовать эту функцию. Достаточно простого вызова cv2.cvtColor: img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) сработает. Пожалуйста, прочтите документацию по этой функции, прежде чем использовать ее в следующий раз. Это стандартный навык, который необходимо освоить всем разработчикам при использовании чужого кода. - person rayryeng; 12.08.2015

Как говорится в сообщении об ошибке, DRAW_MATCHES_FLAGS_DEFAULT имеет тип «длинный». Это константа, определяемая модулем cv2, а не функция. К сожалению, нужная вам функция «drawMatches» существует только в интерфейсе OpenCV C++.

person Anonymous    schedule 02.07.2012
comment
Больше не правда. Теперь он существует в OpenCV 3.x и 4.x. Однако приведенные выше ответы являются обходными путями для OpenCV 2.x. - person rayryeng; 18.12.2019