web-dev-qa-db-ja.com

module 'オブジェクトには属性' drawMatches 'がありませんopencv python

OpenCVでの機能検出の例を行っています。この例を以下に示します。次のエラーが表示されます

モジュール 'オブジェクトには属性' drawMatches 'がありません

OpenCV Docsを確認しましたが、なぜこのエラーが発生するのかわかりません。誰が理由を知っていますか?

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'
45
Javed

drawMatches関数はPythonインターフェイスの一部ではありません。
ドキュメント でわかるように、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 [〜#〜]

5か月前にこの機能を導入した commit が実際にありました。ただし、公式ドキュメントには(まだ)ありません。
最新のOpenCVバージョン(2.4.7)を使用していることを確認してください。完全を期すため、OpenCV 3.0.0のFunctionsインターフェースは this のようになります。

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

私もパーティーに遅れていますが、Mac OS X用のOpenCV 2.4.9をインストールしましたが、drawMatches関数は私のディストリビューションには存在しません。また、find_objで2番目のアプローチを試しましたが、それでもうまくいきませんでした。それで、drawMatchesを真似た実装を自分の能力で最大限に作成することにしました。これが私が作成したものです。

一方はカメラマンで、もう一方は同じ画像ですが、反時計回りに55度回転した独自の画像を提供しました。

私が書いたものの基本は、出力画像に両方の画像を配置するのに対応するために行の量が2つの画像の最大である出力RGB画像を割り当て、列は単に両方の列の合計であるということです。私は両方の画像がグレースケールであると仮定することに注意してください。

各画像を対応するスポットに配置し、一致したすべてのキーポイントのループを実行します。 2つの画像間で一致したキーポイントを抽出し、それらの(x,y)座標を抽出します。検出された各場所に円を描き、これらの円を結ぶ線を引きます。

2番目の画像で検出されたキーポイントは、独自の座標系に関するものであることに注意してください。これを最終的な出力画像に配置する場合は、列座標が出力画像の座標系と一致するように、列座標を最初の画像の列の量だけオフセットする必要があります。

難しい話は抜きにして:

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]

    # 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

これが機能することを説明するために、使用した2つの画像を次に示します。

Cameraman Image

Rotated Cameraman Image

OpenCVのORB検出器を使用してキーポイントを検出し、正規化されたハミング距離をバイナリ記述子であるため、類似性の距離測定として使用しました。など:

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


cv2.BFMatcherknnMatchで使用するには

一致が1Dリストに表示されると仮定した場合にのみ上記のコードが機能することに注意してください。ただし、たとえばcv2.BFMatcherknnMatchメソッドを使用することにした場合、返されるのはリストのリストです。具体的には、img1の記述子がdes1と呼ばれ、img2の記述子がdes2と呼ばれる場合、knnMatchから返されるリストの各要素はkは、des2の各記述子に最も近いdes1から一致します。したがって、knnMatchの出力の最初の要素は、des2で見つかった最初の記述子に最も近いdes1からのk一致のリストです。 knnMatchの出力の2番目の要素は、des2で見つかった2番目の記述子に最も近いdes1からのkマッチのリストです。

knnMatchを最も意味のあるものにするために、mustは、k=2に一致するネイバーの合計量を制限します。理由は、少なくとも2つの一致したポイントを使用して一致の品質を確認し、品質が十分であれば、これらを使用して一致を描画し、画面に表示するためです。 des2からdes1の記述子までの最初に一致したポイントからの距離が一定の距離であることを確認するために、非常に単純な比率テスト(クレジットは David Lowe になります)を使用できますdes2から2番目に一致したポイントと比較して離れています。したがって、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関数はありません

78
rayryeng

この質問には正しい答えがありますが、3.0(-dev)ではなくOpenCV 2.4.8を使用している場合、回避策は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

16
PhilWilliammee