Подтвердить что ты не робот

Модуль 'не имеет атрибута' drawMatches 'opencv python

Я просто делаю пример обнаружения функции в OpenCV. Этот пример показан ниже. Это дает мне следующую ошибку:

модуль 'объект не имеет атрибута' drawMatches '

Я проверил документы OpenCV и не знаю, почему я получаю эту ошибку. Кто-нибудь знает, почему?

import numpy as np
import cv2
import matplotlib.pyplot as plt

img1 = cv2.imread('box.png',0)          # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage

# Initiate SIFT detector
orb = cv2.ORB()

# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

# Match descriptors.
matches = bf.match(des1,des2)

# Draw first 10 matches.
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)

plt.imshow(img3),plt.show()

Ошибка:

Traceback (most recent call last):
File "match.py", line 22, in <module>
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)
AttributeError: 'module' object has no attribute 'drawMatches'
4b9b3361

Ответ 1

Функция drawMatches не является частью интерфейса Python.
Как вы можете видеть в docs, он определен только для C++ на данный момент.

Выдержка из документов:

 C++: void drawMatches(const Mat& img1, const vector<KeyPoint>& keypoints1, const Mat& img2, const vector<KeyPoint>& keypoints2, const vector<DMatch>& matches1to2, Mat& outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector<char>& matchesMask=vector<char>(), int flags=DrawMatchesFlags::DEFAULT )
 C++: void drawMatches(const Mat& img1, const vector<KeyPoint>& keypoints1, const Mat& img2, const vector<KeyPoint>& keypoints2, const vector<vector<DMatch>>& matches1to2, Mat& outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector<vector<char>>& matchesMask=vector<vector<char> >(), int flags=DrawMatchesFlags::DEFAULT )

Если функция имела интерфейс Python, вы бы нашли что-то вроде этого:

 Python: cv2.drawMatches(img1, keypoints1, [...]) 

EDIT

На самом деле был commit, который ввел эту функцию 5 месяцев назад. Однако в официальной документации это еще не указано. Убедитесь, что вы используете новейшую версию OpenCV (2.4.7). Для полноты интерфейса функций для OpenCV 3.0.0 будет выглядеть как this:

cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2[, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]]]) → outImg

Ответ 2

Я тоже опаздываю на вечеринку, но я установил OpenCV 2.4.9 для Mac OS X, а функция drawMatches не существует в моем дистрибутиве. Я также попробовал второй подход с find_obj, и это тоже не сработало. При этом я решил написать свою собственную реализацию, которая максимально подражает 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 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]

    # Create the output image
    # The rows of the output are the largest between the two images
    # and the columns are simply the sum of the two together
    # The intent is to make this a colour image, so make this 3 channels
    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:] = 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.destroyWindow('Matched Features')

    # Also return the image if you'd like a copy
    return out

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

Cameraman Image

Rotated Cameraman Image

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

import numpy as np
import cv2

img1 = cv2.imread('cameraman.png', 0) # Original image - ensure grayscale
img2 = cv2.imread('cameraman_rot55.png', 0) # Rotated image - ensure grayscale

# 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 - also save a copy for use later
out = drawMatches(img1, kp1, img2, kp2, matches[:10])

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

Matched Features


Использовать с knnMatch из cv2.BFMatcher

Я хотел бы отметить, что приведенный выше код работает, только если вы предполагаете, что совпадения отображаются в 1D-списке. Однако, если вы решили использовать метод knnMatch из cv2.BFMatcher, например, то, что возвращается, является списком списков. В частности, с учетом дескрипторов в img1, называемых des1 и дескрипторов в img2, называемых des2, каждый элемент в списке, возвращаемом из knnMatch, является еще одним списком k, совпадающим с des2, которые являются ближе всего к каждому дескриптору в des1. Поэтому первым элементом из вывода knnMatch является список из k, совпадающий с des2, который был самым близким к первому дескриптору, найденному в des1. Второй элемент из вывода knnMatch - это список из k совпадений из des2, которые были наиболее близки ко второму дескриптору, найденному в des1 и т.д.

Чтобы максимально использовать knnMatch, вы должны ограничить общее количество соседей в соответствии с k=2. Причина в том, что вы хотите использовать по крайней мере две согласованные точки, чтобы проверить качество матча, и если качество достаточно хорошее, вы хотите использовать их, чтобы нарисовать свои спички и показать их на экране. Вы можете использовать очень простой тест отношения (кредит идет на David Lowe), чтобы убедиться, что расстояние от первой совпадающей точки от des2 до дескриптор в des1 находится на некотором расстоянии по сравнению со второй совпадающей точкой из des2. Поэтому, чтобы повернуть то, что возвращается от knnMatch, к тому, что требуется с кодом, который я написал выше, повторить по совпадениям, использовать вышеупомянутый тест отношения и проверить, проходит ли он. Если это так, добавьте первую сопоставленную ключевую точку в новый список.

Предполагая, что вы создали все переменные, как вы делали до объявления экземпляра BFMatcher, вы должны сделать это, чтобы адаптировать метод knnMatch для использования drawMatches:

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

# Perform KNN matching
matches = bf.knnMatch(des1, des2, k=2)

# Apply ratio test
good = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
       # Add first matched keypoint to list
       # if ratio test passes
       good.append(m)

# Or do a list comprehension
#good = [m for (m,n) in matches if m.distance < 0.75*n.distance]

# Now perform drawMatches
out = drawMatches(img1, kp1, img2, kp2, good)

Я хочу связать вышеуказанные изменения с пользователем @ryanmeasel и ответ, что эти изменения были найдены, находится в его сообщении: OpenCV Python: нет функции drawMatchesknn.

Ответ 3

Я знаю, что этот вопрос имеет правильный ответ, но если вы используете OpenCV 2.4.8, а не 3.0 (-dev), обходным решением может быть использование некоторых функций из включенных образцов, найденных в opencv\sources\samples\python2\find_obj

import cv2
from find_obj import filter_matches,explore_match

img1 = cv2.imread('../c/box.png',0)          # queryImage
img2 = cv2.imread('../c/box_in_scene.png',0) # trainImage

# Initiate SIFT detector
orb = cv2.ORB()

# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING)#, crossCheck=True)

matches = bf.knnMatch(des1, trainDescriptors = des2, k = 2)
p1, p2, kp_pairs = filter_matches(kp1, kp2, matches)
explore_match('find_obj', img1,img2,kp_pairs)#cv2 shows image

cv2.waitKey()
cv2.destroyAllWindows()

Это выходное изображение:

enter image description here