2012-06-20 6 views
8

Sto cercando di usare opencv con python. Ho scritto un codice descrittivo (SIFT, SURF o ORB) in versione C++ di opencv 2.4. Voglio convertire questo codice in opencv con python. Ho trovato alcuni documenti su come usare le funzioni opencv in C++ ma molte delle funzioni opencv in python non riuscivo a trovare il modo di usarle. Ecco il mio codice Python, e il mio problema attuale è che non so come usare "drawMatches" di opencv C++ in python. Ho trovato cv2.DRAW_MATCHES_FLAGS_DEFAULT ma non ho idea di come usarlo. Ecco il mio codice python di corrispondenti usando descrittori di ORB:Come visualizzare la corrispondenza dei descrittori usando il modulo opencv in python

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

Messaggio di errore della linea "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 

ho trascorso molto tempo di ricerca documentazione ed esempi di utilizzo delle funzioni opencv con python. Tuttavia, sono molto frustrato perché ci sono pochissime informazioni sull'uso delle funzioni opencv in python. Sarà estremamente utile se qualcuno mi può insegnare dove posso trovare la documentazione su come usare ogni funzione del modulo opencv in python. Apprezzo il tuo tempo e il tuo aiuto.

risposta

2

Come il messaggio di errore dice, DRAW_MATCHES_FLAGS_DEFAULT è di tipo 'lunga'. È una costante definita dal modulo cv2, non una funzione. Sfortunatamente, la funzione che vuoi, 'drawMatches' esiste solo nell'interfaccia C++ di OpenCV.

+0

Grazie per la risposta !! – user1433201

14

è possibile visualizzare la funzionalità di corrispondenza in Python come segue. Nota l'uso della libreria 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

Quando eseguo il codice, ricevo un errore sulla riga 66, '' 'TypeError: argomento integer previsto, ottenuto float''' – gilbertbw

+0

@ wall-e un utente anonimo ha appena modificato il tuo post, potrebbe voler controllare che non l'abbiano interrotto – OGHaza

+0

view [: h1,: w1,:] = img1 ValueError: impossibile trasmettere l'array di input da forma (322,518) in forma (322,518,3) – Giuseppe

9

Ho anche scritto qualcosa di me stesso che utilizza solo l'interfaccia OpenCV Python e non ho usato scipy. drawMatches fa parte di OpenCV 3.0.0 e non fa parte di OpenCV 2, che è quello che sto attualmente utilizzando. Anche se sono in ritardo per la festa, ecco la mia implementazione che riproduce lo drawMatches al meglio delle mie possibilità.

ho fornito le mie immagini in cui uno è di un uomo della macchina fotografica, e l'altro è la stessa immagine, ma ruotata di 55 gradi in senso antiorario.

La premessa di base di ciò che ho scritto è che io allocare un'immagine d'uscita RGB, dove la quantità di righe è il massimo delle due immagini per ospitare dell'immissione entrambe le immagini l'immagine di uscita e le colonne sono semplicemente la somma di entrambe le colonne insieme. Metto ogni immagine nei punti corrispondenti, quindi eseguo un ciclo di tutti i punti chiave corrispondenti. Estraggo i punti chiave corrispondenti tra le due immagini, quindi estraiamo le loro coordinate (x,y). Quindi disegno cerchi in ciascuna delle posizioni rilevate, quindi disegna una linea che collega questi cerchi insieme.

tenga presente che il punto chiave rilevato nella seconda immagine è rispetto al proprio sistema di coordinate. Se si desidera inserirlo nell'immagine di output finale, è necessario sfalsare la coordinata della colonna in base alla quantità di colonne della prima immagine in modo che la coordinata della colonna sia rispetto al sistema di coordinate dell'immagine di output .

Senza ulteriori indugi:

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

Per illustrare che questo funziona, qui ci sono le due immagini che ho usato:

enter image description here

enter image description here

ho usato OpenCV di Rivelatore ORB per rilevare i punti chiave, e ha usato la distanza normalizzata di Hamming come misura della distanza per similarità in quanto questo è un descrittore binario. In quanto tale:

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

Questa è l'immagine che ottengo:

enter image description here

+0

Hii @rayryeng Quando sto cercando di eseguire il codice sopra, sto ricevendo Traceback (ultima chiamata ultima) : File "orb1.py", riga 33, in out [: rows1,: cols1 ,:] = np.dstack ([img1, img1, img1]) ValueError: impossibile trasmettere l'array di input dalla forma (900 , 1440,9) in forma (900,1440,3) –

+2

@BhushanPatil - Leggere attentamente la docstring della funzione ** **. Richiede immagini in scala di grigi. Stai utilizzando ** immagini RGB **. È necessario convertire le immagini in scala di grigi prima di utilizzare la funzione. Una semplice chiamata 'cv2.cvtColor' dovrebbe essere sufficiente:' img = cv2.cvtColor (img, cv2.COLOR_BGR2GRAY) 'funzionerà. Per favore leggi la documentazione della funzione prima di usarla la prossima volta. Questa è una competenza standard che tutti gli sviluppatori devono imparare quando usano il codice di qualcun altro. – rayryeng

Problemi correlati