I am trying to find a way to determine how much rotation a detected object in a scene is compared to the template image. It is not quite right, and need some help with this or if there is a better way, that would be great. Thanks.
I just want to test if the icons are oriented correcly:
Here is some code:
import numpy as np
import cv2
from matplotlib import pyplot as plt
def feature_detect_with_orb2(train_img_path, scene_img_path):
# Read the query image as query_img (to find) and train image (to be found in)
train_img = cv2.imread(train_img_path)
query_img = cv2.imread(scene_img_path)
# Convert it to grayscale
query_img_bw = cv2.cvtColor(query_img, cv2.COLOR_BGR2GRAY)
train_img_bw = cv2.cvtColor(train_img, cv2.COLOR_BGR2GRAY)
# Initialize the ORB detector algorithm with increased number of features
patchSizeEdgeThreshold = 15
features = 10000
scaleFactor = 1.2
levels = 8
edgeThreshold = patchSizeEdgeThreshold
fistLevel = 0
wta = 2
scoreType=cv2.ORB_FAST_SCORE
patchSize = patchSizeEdgeThreshold
fastThrshold = 15
orb = cv2.ORB_create(
nfeatures=features, # Increase the number of features to detect
scaleFactor=scaleFactor, # A smaller scale factor to create more levels in the pyramid
nlevels=levels, # Increase the number of levels in the pyramid
edgeThreshold=edgeThreshold, # Default value, but can be adjusted based on image borders
firstLevel=fistLevel, # Default value, the level of the pyramid to start from
WTA_K=wta, # The default value, producing binary strings from comparisons of pairs of points
scoreType=scoreType,
patchSize=patchSize, # Size of the patch used by the oriented BRIEF descriptor
fastThreshold=fastThrshold # Threshold for the FAST keypoint detector
)
# Now detect the keypoints and compute the descriptors for the query image and train image
queryKeypoints, queryDescriptors = orb.detectAndCompute(query_img_bw, None)
trainKeypoints, trainDescriptors = orb.detectAndCompute(train_img_bw, None)
# Check if descriptors were found
if queryDescriptors is not None and trainDescriptors is not None:
# Initialize the Matcher for matching the keypoints and then match the keypoints
if(orb.getWTA_K() > 2):
matcher = cv2.BFMatcher(cv2.NORM_HAMMING2, crossCheck=True)
else:
matcher = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = matcher.match(queryDescriptors, trainDescriptors)
# Sort the matches based on distance. Less distance means better match
matches = sorted(matches, key=lambda x: x.distance)
if len(matches) > 4:
# Extract location of good matches
points_query = np.float32([queryKeypoints[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
points_train = np.float32([trainKeypoints[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)
# Find homography
homography, mask = cv2.findHomography(points_query, points_train, cv2.RANSAC)
if homography is not None:
# Extract the rotation part of the homography matrix
rotation_matrix = homography[:3, :3]
# Compute the rotation angle in radians
theta_radians = np.arctan2(rotation_matrix[1, 0], rotation_matrix[0, 0])
# Convert the rotation angle to degrees
print('Angle: ' + str(np.degrees(theta_radians)))
# Transform the corners of the query image to the scene image
h, w = query_img_bw.shape
corners_query_img = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
transformed_corners = cv2.perspectiveTransform(corners_query_img, homography)
# Draw bounding box in the scene image
detected_img = cv2.polylines(train_img, [np.int32(transformed_corners)], True, (255,0,0), 3, cv2.LINE_AA)
# draw the matches to the final image containing both the images
# the drawMatches() function takes both images and keypoints and outputs the matched query image with its train image
final_img = cv2.drawMatches(query_img, queryKeypoints, train_img, trainKeypoints, matches[:count], None)
for i, match in enumerate(matches[:count]): # Limiting to the top 50 matches for readability
query_idx = match.queryIdx
train_idx = match.trainIdx
query_pt = queryKeypoints[query_idx].pt # Coordinates in the query (template) image
train_pt = trainKeypoints[train_idx].pt # Coordinates in the train (scene) image
#print(f"Match {i+1}: Query Image Coord = {query_pt}, Train Image Coord = {train_pt}")
# Resize the final image for display
final_img = cv2.resize(final_img, (1000,650))
# Show the final image using matplotlib
plt.imshow(cv2.cvtColor(final_img, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.show()
# When done, destroy the windows opened by OpenCV
cv2.destroyAllWindows()
else:
print("Descriptors not found in one or both images.")