2012-06-20 24 views
8

Estoy tratando de usar opencv con python. Escribí un código de coincidencia de descriptor (SIFT, SURF u ORB) en la versión C++ de opencv 2.4. Quiero convertir este código a opencv con python. Encontré algunos documentos sobre cómo usar las funciones de opencv en C++ pero muchas de las funciones de opencv en python no pude encontrar cómo usarlas. Aquí está mi código python, y mi problema actual es que no sé cómo usar "drawMatches" de opencv C++ en python. Encontré cv2.DRAW_MATCHES_FLAGS_DEFAULT pero no tengo idea de cómo usarlo. Aquí está mi código Python de juego utilizando descriptores ORB:Cómo visualizar la coincidencia de descriptores usando el módulo opencv en 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); 

Mensaje de error de la línea "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 

pasé mucho tiempo de búsqueda de documentación y ejemplos de uso de funciones de OpenCV con Python. Sin embargo, estoy muy frustrado porque hay muy poca información sobre el uso de las funciones de OpenCV en Python. Será extremadamente útil si alguien puede enseñarme dónde puedo encontrar la documentación de cómo usar cada función del módulo opencv en Python. Aprecio tu tiempo y ayuda.

Respuesta

2

Como dice el mensaje de error, DRAW_MATCHES_FLAGS_DEFAULT es del tipo 'long'. Es una constante definida por el módulo cv2, no una función. Desafortunadamente, la función que desea, 'drawMatches' solo existe en la interfaz C++ de OpenCV.

+0

Gracias por su respuesta !! – user1433201

14

puede visualizar la coincidencia de funciones en Python de la siguiente manera. Tenga en cuenta el uso de la biblioteca 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

Al ejecutar su código, aparece un error en la línea 66, '' 'TypeError: argumento entero esperado, got float''' – gilbertbw

+0

@ wall-e un usuario anónimo acaba de editar su publicación, puede que quiera comprobar que no lo han roto – OGHaza

+0

view [: h1,: w1,:] = img1 ValueError: no se pudo transmitir la matriz de entrada de la forma (322,518) en la forma (322,518,3) – Giuseppe

9

También he escrito algo a mí mismo que sólo utiliza la interfaz de OpenCV Python y que no usamos scipy. drawMatches es parte de OpenCV 3.0.0 y no es parte de OpenCV 2, que es lo que estoy usando actualmente. Aunque llego tarde a la fiesta, aquí está mi propia implementación que imita el drawMatches de la mejor manera posible.

He proporcionado mis propias imágenes, donde una es de un hombre de la cámara, y la otra es la misma imagen, pero girada en sentido contrario a las agujas del reloj 55 grados.

La premisa básica de lo que escribí es que asigno una imagen RGB de salida donde la cantidad de filas es el máximo de las dos imágenes para acomodar las dos imágenes en la imagen de salida y las columnas son simplemente la suma de ambas columnas juntas. Coloco cada imagen en sus lugares correspondientes, luego corro a través de un bucle de todos los puntos clave coincidentes. Extraigo los puntos clave que coinciden entre las dos imágenes, luego extraigo sus coordenadas (x,y). Luego dibujo círculos en cada una de las ubicaciones detectadas, luego trazo una línea que conecta estos círculos.

Tenga en cuenta que el punto clave detectado en la segunda imagen es con respecto a su propio sistema de coordenadas. Si desea colocar esto en la imagen final de salida, necesita desplazar la columna coordinada por la cantidad de columnas de la primera imagen para que la columna coordinada sea con respecto al sistema de coordenadas de la imagen de salida .

Sin más preámbulos:

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

para ilustrar que esto funciona, aquí están las dos imágenes que he utilizado:

enter image description here

enter image description here

utilicé de OpenCV Detector ORB para detectar los puntos clave, y usó la distancia de Hamming normalizada como la medida de distancia para similitud ya que este es un descriptor binario. Como tal:

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

Ésta es la imagen me sale:

enter image description here

+0

Hii @rayryeng Cuando intento ejecutar el código anterior, recibo Trazabilidad (última llamada más reciente) : archivo "orb1.py", línea 33, en fuera [: rows1,: cols1 ,:] = np.dstack ([img1, img1, img1]) ValueError: no se pudo transmitir matriz de entrada de forma (900 , 1440,9) en forma (900,1440,3) –

+2

@BhushanPatil - Lea la cadena de documentación de la función ** con cuidado **. Requiere imágenes en escala de grises. Está utilizando imágenes ** RGB **. Necesita convertir las imágenes a escala de grises antes de usar la función. Una simple llamada 'cv2.cvtColor' debería ser suficiente:' img = cv2.cvtColor (img, cv2.COLOR_BGR2GRAY) 'funcionará. Lea la documentación de la función antes de usarla la próxima vez. Esta es una habilidad estándar que todos los desarrolladores deben aprender al usar el código de otra persona. – rayryeng

Cuestiones relacionadas