2012-06-20 16 views
8

Próbuję użyć opencv z python. Napisałem kod deskryptora (SIFT, SURF lub ORB) w wersji C++ opencv 2.4. Chcę przekonwertować ten kod na opencv z pythonem. Znalazłem kilka dokumentów o tym, jak używać funkcji opencv w C++, ale wiele funkcji opencv w Pythonie nie mogłem znaleźć sposobu ich użycia. Oto mój kod Pythona, a moim obecnym problemem jest to, że nie wiem jak używać "drawMatches" opencv C++ w pythonie. Znalazłem cv2.DRAW_MATCHES_FLAGS_DEFAULT, ale nie mam pojęcia, jak z niego korzystać. Oto mój kod python zgodnych z wykorzystaniem deskryptorów ORB:Jak wizualizować dopasowanie deskryptorów przy użyciu modułu opencv w pythonie

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); 

Komunikat o błędzie linii "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 

Spędziłem dużo czasu na poszukiwanie dokumentacji i przykłady używania funkcji opencv w pythonie. Jednak jestem bardzo sfrustrowany, ponieważ jest bardzo mało informacji o używaniu funkcji opencv w pythonie. Będzie bardzo pomocne, jeśli ktoś nauczy mnie, gdzie mogę znaleźć dokumentację, jak korzystać z każdej funkcji modułu opencv w pythonie. Doceniam twój czas i pomoc.

Odpowiedz

2

Jak informuje komunikat o błędzie, DRAW_MATCHES_FLAGS_DEFAULT ma typ "long". Jest to stała określona przez moduł cv2, a nie funkcja. Niestety, wybrana funkcja "drawMatches" istnieje tylko w interfejsie C++ OpenCV.

+0

Dzięki za odpowiedź !! – user1433201

14

można wizualizować dopasowanie funkcji w Pythonie w następujący sposób. Zwróć uwagę na użycie biblioteki 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() 
+0

Po uruchomieniu kodu pojawia się błąd w linii 66, oczekiwany jest argument '' 'TypeError: integer, float'''''''' – gilbertbw

+0

@ wall-e anonimowy użytkownik właśnie edytował swój wpis, może chcieć sprawdzić, czy go nie złamał – OGHaza

+0

view [: h1,: w1,:] = img1 ValueError: nie można wysyłać tablicy wejściowej z kształtu (322,518) do kształtu (322,518,3) – Giuseppe

9

ja też sobie coś napisane, że po prostu wykorzystuje interfejs OpenCV Python i nie korzystać scipy. drawMatches jest częścią OpenCV 3.0.0 i nie jest częścią OpenCV 2, którego aktualnie używam. Mimo że spóźniam się na imprezę, oto moja własna implementacja, która naśladuje drawMatches najlepiej jak potrafię.

Dostarczyłem własne obrazy, w których jeden jest z kamery, a drugi to ten sam obraz, ale obrócony o 55 stopni w kierunku przeciwnym do ruchu wskazówek zegara.

Podstawowym założeniem tego, co napisałem, jest to, że przydzielam wyjściowy obraz RGB, w którym liczba wierszy jest maksymalną z dwóch obrazów, aby pomieścić oba obrazy w wyjściowym obrazie, a kolumny są po prostu podsumowaniem obu kolumn razem. Umieszczam każdy obraz w odpowiednich miejscach, a następnie przechodzę przez pętlę wszystkich dopasowanych punktów kluczowych. Wyodrębniam punkty kluczowe pasujące między dwoma obrazami, a następnie wyprowadzam ich współrzędne. Następnie rysuję koła w każdej z wykrytych lokalizacji, a następnie narysuję linię łączącą te kręgi.

Należy pamiętać, że wykryty punkt kluczowy na drugim obrazie odnosi się do własnego układu współrzędnych. Jeśli chcesz umieścić to w ostatecznym obrazie wyjściowym, musisz przesunąć współrzędne kolumny przez liczbę kolumn z pierwszego obrazu tak, aby współrzędne kolumny były zgodne z układem współrzędnych obrazu wyjściowego .

Bez zbędnych ceregieli:

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() 

aby pokazać, że to działa, tu są dwa obrazy, które użyłem:

enter image description here

enter image description here

użyłem OpenCV-tych Detektor ORB do wykrywania punktów kluczowych, i użył znormalizowanej odległości Hamminga jako miary odległości dla podobieństwa, ponieważ jest to deskryptor binarny. Jako takie:

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]) 

Jest to obraz pojawia się:

enter image description here

+0

Hii @rayryeng Kiedy próbuję uruchomić powyższy kod, otrzymuję Traceback (ostatnie ostatnie połączenie) : Plik "orb1.py", wiersz 33, w out [: rows1,: cols1 ,:] = np.dstack ([img1, img1, img1]) ValueError: nie można rozgłaszać tablicy wejściowej z kształtu (900 , 1440,9) w kształt (900, 1440,3) –

+2

@ BushushanPatil - Przeczytaj docstring funkcji ** ostrożnie **. Wymaga obrazów w skali szarości. Używasz ** zdjęć RGB **. Przed użyciem funkcji należy przekonwertować obrazy na skalę szarości. Wystarczy proste wywołanie 'cv2.cvtColor': img = cv2.cvtColor (img, cv2.COLOR_BGR2GRAY)' zadziała. Proszę przeczytać dokumentację funkcji przed następnym użyciem. Jest to standardowa umiejętność, której wszyscy programiści muszą się nauczyć, posługując się czyimś kodem. – rayryeng