thresholding machine learning imagen color_bgr2gray book binarizar python image opencv image-processing computer-vision

machine - módulo ''objeto no tiene atributo'' drawMatches ''opencv python



python opencv contour (3)

Solo estoy haciendo un ejemplo de detección de características en OpenCV. Este ejemplo se muestra a continuación. Me está dando el siguiente error

módulo ''objeto no tiene atributo'' drawMatches ''

Revisé los documentos de OpenCV y no estoy seguro de por qué recibo este error. ¿Alguien sabe por qué?

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

Error:

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


La función drawMatches no es parte de la interfaz de Python.
Como puede ver en los docs , solo está definido para C++ en este momento.

Extracto de los documentos:

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 )

Si la función tiene una interfaz de Python, encontrará algo como esto:

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

EDITAR

En realidad, hubo un commit que introdujo esta función hace 5 meses. Sin embargo, no está (todavía) en la documentación oficial.
Asegúrese de estar utilizando la versión más nueva de OpenCV (2.4.7). En aras de la integridad, la interfaz de Funciones para OpenCV 3.0.0 se verá así:

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


Llego tarde a la fiesta también, pero instalé OpenCV 2.4.9 para Mac OS X, y la función drawMatches no existe en mi distribución. También probé el segundo enfoque con find_obj y tampoco me funcionó. Con eso, decidí escribir mi propia implementación que imita drawMatches lo mejor que puedo y esto es lo que he producido.

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 55 grados en sentido antihorario.

Lo básico 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 . Tenga en cuenta que supongo que ambas imágenes son en escala de grises.

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) . Dibujé círculos en cada una de las ubicaciones detectadas, luego dibujé una línea que conectaba 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 de salida final, necesita desplazar la coordenada de la columna por la cantidad de columnas de la primera imagen para que la coordenada de la columna esté 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] # 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

Para ilustrar que esto funciona, aquí están las dos imágenes que utilicé:

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

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

Esta es la imagen que obtengo:

Para usar con knnMatch desde cv2.BFMatcher

Me gustaría hacer una nota donde el código anterior solo funciona si se supone que las coincidencias aparecen en una lista 1D. Sin embargo, si decide utilizar el método knnMatch de cv2.BFMatcher por ejemplo, lo que se devuelve es una lista de listas. Específicamente, dados los descriptores en img1 llamados img1 y los descriptores en img2 llamados des2 , cada elemento en la lista devuelto por knnMatch es otra lista de k coincidencias de des2 que son las más cercanas a cada descriptor en des1 . Por lo tanto, el primer elemento de la salida de knnMatch es una lista de k coincidencias de des2 que fueron las más cercanas al primer descriptor encontrado en des1 . El segundo elemento de la salida de knnMatch es una lista de k coincidencias de des2 que fueron las más cercanas al segundo descriptor encontrado en des1 y así sucesivamente.

Para que knnMatch tenga más sentido, debe limitar la cantidad total de vecinos para que coincida con k=2 . La razón es porque quiere usar al menos dos puntos coincidentes para verificar la calidad del partido y si la calidad es lo suficientemente buena, querrá usarlos para dibujar sus partidos y mostrarlos en la pantalla. Puede usar una prueba de relación muy simple (el crédito va para David Lowe ) para asegurar que la distancia desde el primer punto coincidente desde des2 hasta el descriptor en des1 esté a cierta distancia en comparación con el segundo punto coincidente de des2 . Por lo tanto, para convertir lo que se devuelve de knnMatch a lo que se requiere con el código que escribí arriba, repita las coincidencias, use la prueba de relación anterior y verifique si pasa. Si lo hace, agregue el primer punto clave coincidente a una nueva lista.

Suponiendo que haya creado todas las variables como lo hizo antes de declarar la instancia de BFMatcher , ahora haría esto para adaptar el método knnMatch para usar 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)

Quiero atribuir las modificaciones anteriores al usuario @ryanmeasel y la respuesta de que se encontraron estas modificaciones está en su publicación: OpenCV Python: sin función drawMatchesknn .


Sé que esta pregunta tiene una respuesta aceptada que es correcta, pero si está utilizando OpenCV 2.4.8 y no 3.0 (-dev), una solución podría ser usar algunas funciones de las muestras incluidas que se encuentran en 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()

Esta es la imagen de salida: