How to Extract X,Y Coordinates from Opencv "Cv2.Keypoint" Object

how to extract x,y coordinates from OpenCV "cv2.keypoint" object?

You can use:

import numpy as np

pts = np.float([key_point.pt for key_point in kp]).reshape(-1, 1, 2)

pts will be an array of keypoints.

OpenCV return keypoints coordinates and area from blob detection, Python

The pt property:

keypoints = detector.detect(frame) #list of blobs keypoints
x = keypoints[i].pt[0] #i is the index of the blob you want to get the position
y = keypoints[i].pt[1]

Some documentation

How to get pixel coordinates from Feature Matching in OpenCV Python

We know that your keypoints are stored in kp1 and kp2 where they are lists of feature matches for the first and second image respectively. In the cv2.ORB perspective, the feature descriptors are 2D matrices where each row is a keypoint that is detected in the first and second image.

In your case because you are using cv2.BFMatch, matches returns a list of cv2.DMatch objects where each object contains several members and among them are two important members:

  • queryIdx - The index or row of the kp1 interest point matrix that matches
  • trainIdx - The index or row of the kp2 interest point matrix that matches

Therefore, queryIdx and trainIdx tell you which ORB features match between the first and second image. You'd use these to index into kp1 and kp2 and obtain the pt member, which is a tuple of (x,y) coordinates that determine the actual spatial coordinates of the matches.

All you have to do is iterate through each cv2.DMatch object in matches, append to a list of coordinates for both kp1 and kp2 and you're done.

Something like this:

# Initialize lists
list_kp1 = []
list_kp2 = []

# For each match...
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
# Get the coordinates
(x1, y1) = kp1[img1_idx].pt
(x2, y2) = kp2[img2_idx].pt

# Append to each list
list_kp1.append((x1, y1))
list_kp2.append((x2, y2))

Note that I could have just done list_kp1.append(kp1[img1_idx].pt) and the same for list_kp2, but I wanted to make it very clear on how to interpret the spatial coordinates. You could also go one step further and do a list comprehension:

list_kp1 = [kp1[mat.queryIdx].pt for mat in matches] 
list_kp2 = [kp2[mat.trainIdx].pt for mat in matches]

list_kp1 will contain the spatial coordinates of a feature point that matched with the corresponding position in list_kp2. In other words, element i of list_kp1 contains the spatial coordinates of the feature point from img1 that matched with the corresponding feature point from img2 in list_kp2 whose spatial coordinates are in element i.


As a minor sidenote, I used this concept when I wrote a workaround for drawMatches because for OpenCV 2.4.x, the Python wrapper to the C++ function does not exist, so I made use of the above concept in locating the spatial coordinates of the matching features between the two images to write my own implementation of it.

Check it out if you like!

module' object has no attribute 'drawMatches' opencv python

How to manually set keypoints and extract features

Use the compute method in the orb API. Something standard would be

kp = orb.detect(img,None)
kp, des = orb.compute(img, kp)

But for your case, key points come from user input so use something like

input_kp = # comes from user
kp, des = orb.compute(img, input_kp)

Make sure that the input keypoints match the format that the compute method is expecting. You can create a key point from x, y values like this.

key_points = [cv2.KeyPoint(x1, y1, 1), cv2.KeyPoint(x2, y2, 1) ...]

How to obtain (x,y) coordinates of a shape found using mask in OpenCV, Python?

You can binarise image and then apply some morphological operations to get the proper connected components. Here is an approach. You can fine-tune this to get proper output.

import numpy as np
import cv2
import os
image=cv2.imread('path/to/image.jpg')
###binarising
gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
ret2,th2 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

###applying morphological operations to dilate the image
kernel=np.ones((3,3),np.uint8)
dilated=cv2.dilate(th2,kernel,iterations=3)

### finding contours, can use connectedcomponents aswell
_,contours,_ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

### converting to bounding boxes from polygon
contours=[cv2.boundingRect(cnt) for cnt in contours]
### drawing rectangle for each contour for visualising
for cnt in contours:
x,y,w,h=cnt
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)

Normal binary image

binary image

Dilated image

dilated image

output with detected bounding boxes
output with detected bounding boxes

Drawing SIFT keypoints

A simple solution may be: Iterating all keypoints and draw a "+" sign using cv2.drawMarker.

Here is a code sample:

import numpy as np
import cv2


def draw_cross_keypoints(img, keypoints, color):
""" Draw keypoints as crosses, and return the new image with the crosses. """
img_kp = img.copy() # Create a copy of img

# Iterate over all keypoints and draw a cross on evey point.
for kp in keypoints:
x, y = kp.pt # Each keypoint as an x, y tuple https://stackoverflow.com/questions/35884409/how-to-extract-x-y-coordinates-from-opencv-cv2-keypoint-object

x = int(round(x)) # Round an cast to int
y = int(round(y))

# Draw a cross with (x, y) center
cv2.drawMarker(img_kp, (x, y), color, markerType=cv2.MARKER_CROSS, markerSize=5, thickness=1, line_type=cv2.LINE_8)

return img_kp # Return the image with the drawn crosses.


img = cv2.imread("my_img.jpg")
sift = cv2.SIFT_create()
(keypoints, descriptors) = sift.detectAndCompute(img, None)
#img_kp = cv2.drawKeypoints(img, keypoints, cv2.DRAW_MATCHES_FLAGS_DEFAULT, color=(120,157,187))
img_kp = draw_cross_keypoints(img, keypoints, color=(120,157,187)) # Draw keypoints as "+" signs
cv2.imwrite("img.jpg", img_kp)

Sample result:

Sample Image


Crosses and circles - for testing:

Sample Image

As you can see, the "+" sings are at the centers of the circles.

How do I mask opencv's keypoints post detection?

According to this post, you need to iterate over all keypoints and descriptors and add the good ones to a new list.

There is no possibility to mark them unnecessary.

Here is a sample code:

import numpy as np
import cv2

some_image_file = 'graf.png'

image = cv2.imread(some_image_file)

rows, cols = image.shape[0], image.shape[1]

mask = np.full((rows, cols), 255, np.uint8) # cv2.imread(some_mask_file)
mask_2 = mask.copy() #cv2.imread(some_additional_mask_file)
mask_2[:, 0:cols//2] = 0

# Defining the detector:
detector = cv2.ORB_create(scoreType=cv2.ORB_FAST_SCORE)

# Detecting keypoints inside the initial mask's region:
kp, dsk = detector.detectAndCompute(image, mask)

good_kp = [] # List of "good keypoint"
good_dsk = [] # List of "good descriptors"


# Iterate over all keypoints and descriptors and the good ones to a new list.
# There is no possibility to mark them unnecessary.
# https://stackoverflow.com/questions/29180815/delete-matches-in-opencv-keypoints-and-descriptors
for k, d in zip(kp, dsk):
x, y = k.pt # Each keypoint as an x, y tuple https://stackoverflow.com/questions/35884409/how-to-extract-x-y-coordinates-from-opencv-cv2-keypoint-object

if mask_2[int(y), int(x)] != 0:
good_kp.append(k) # Append keypoint to a list of "good keypoint".
good_dsk.append(d) # Append descriptor to a list of "good descriptors".

# Draw keypoints for testing
image_kp = image.copy()
cv2.drawKeypoints(image, kp, image_kp)

image_good_kp = image.copy()
cv2.drawKeypoints(image, good_kp, image_good_kp)

cv2.imshow('image_kp', image_kp)
cv2.imshow('image_good_kp', image_good_kp)
cv2.waitKey()
cv2.destroyAllWindows()

Input image:

Sample Image

image_kp:

Sample Image

image_good_kp.png (left side keypoints are masked):

Sample Image

How to extract keypoints from Harris Corner Detector using Opencv

Python

This is a how I wrote it in Python:

# convert coordinates to Keypoint type
eye_corner_keypoints = [cv2.KeyPoint(crd[0], crd[1], 13) for crd in eye_corner_coordinates]

# compute SIFT descriptors from corner keypoints
sift = cv2.xfeatures2d.SIFT_create()
eye_corner_descriptors = [sift.compute(gray,[kp])[1] for kp in eye_corner_keypoints]
C++

Looking at the constructor signature in the OpenCV reference documentation for the KeyPoint class:

KeyPoint (float x, float y, float _size, float _angle=-1, float _response=0, int _octave=0, int _class_id=-1)

It looks like you can iterate through your coordinate points and instantiate your KeyPoint objects at each iteration (roughly) like so:

for (int i = 0; i < num_points; i++) {
KeyPoint kp(points_x[i], points_y[i], points_size[i]);
/* ... */

Warning: code is untested, I'm not a C++ programmer.

Pickling cv2.KeyPoint causes PicklingError

The problem is that you cannot dump cv2.KeyPoint to a pickle file. I had the same issue, and managed to work around it by essentially serializing and deserializing the keypoints myself before dumping them with Pickle.

So represent every keypoint and its descriptor with a tuple:

temp = (point.pt, point.size, point.angle, point.response, point.octave, 
point.class_id, desc)

Append all these points to some list that you then dump with Pickle.

Then when you want to retrieve the data again, load all the data with Pickle:

temp_feature = cv2.KeyPoint(x=point[0][0],y=point[0][1],_size=point[1], _angle=point[2], 
_response=point[3], _octave=point[4], _class_id=point[5])
temp_descriptor = point[6]

Create a cv2.KeyPoint from this data using the above code, and you can then use these points to construct a list of features.

I suspect there is a neater way to do this, but the above works fine (and fast) for me. You might have to play around with your data format a bit, as my features are stored in format-specific lists. I tried to present the above using my idea at its generic base. I hope that this may help you.



Related Topics



Leave a reply



Submit