I edited the complete question on 14-3-2023
I am trying to align two images of hands because I want to align one image to a reference image.
For this, I would love to use ICP, but up until now, all my ICP matrixes come back empty.
The preprocessing of the photo's is first to make a mask to seperate the hands from the background.
After that I try to already align the images the best I can using the bounding box technique and to reshape the size to the reference hand after that.
That results into these two pictures:
When using my ICP, the matrix returns empty (see attachment for ICP code). Eventually I expect that the two contours morph as closely to one line of a hand as possible.
What is happening?
I also tried to match the images using the ORB detection algorithm, but then it matches complety wrong points.
Questions are:
- Why does my ICP return empty? (Also the filled in hand instead of a contour returns an empty matrix)
- Is there another technique I could use rather than ICP or ORB?
Please help :)
ICP:
import cv2
import numpy as np
from scipy.spatial import cKDTree
def icp(left_hand, right_hand, num_iterations=20, threshold=0.001):
# Detect keypoints and descriptors
sift = cv2.SIFT_create()
kp1, desc1 = sift.detectAndCompute(left_hand, None)
kp2, desc2 = sift.detectAndCompute(right_hand, None)
# Match keypoints using brute force matching
#bf = cv2.BFMatcher()
#matches = bf.match(desc1, desc2)
#Match keypoints using FLANN matching
flann = cv2.FlannBasedMatcher()
matches = flann.match(desc1, desc2)
# Get corresponding points
left_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)
right_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)
# Initialize transformation matrix
M = np.identity(3)
# Iterative Closest Point algorithm
for i in range(num_iterations):
# Find closest points using KDTree
tree = cKDTree(right_pts.reshape(-1, 2))
dist, indices = tree.query(left_pts.reshape(-1, 2))
# Compute transformation matrix using Singular Value Decomposition (SVD)
A = np.zeros((left_pts.shape[0], 6))
b = np.zeros((left_pts.shape[0], 1))
for j in range(left_pts.shape[0]-1):
x, y = right_pts[indices[j]][0]
A[j] = np.array([left_pts[j][0][0], left_pts[j][0][1], 0, 0, 1, 0])
A[j+1] = np.array([0, 0, left_pts[j][0][0], left_pts[j][0][1], 0, 1])
b[j] = x - left_pts[j][0][0]
b[j+1] = y - left_pts[j][0][1]
x, residuals, rank, s = np.linalg.lstsq(A, b, rcond=None)
delta_M = np.vstack((x.reshape(2, 3), np.array([0, 0, 1])))
#Check if the algorithm has converged
if np.linalg.norm(delta_M - np.identity(3)) < threshold:
break
# Update transformation matrix
M = delta_M.dot(M)
# Transform left points using updated transformation matrix
left_pts = cv2.transform(left_pts, M)
# Warp left hand image to align with right hand image
aligned = cv2.warpPerspective(left_hand, M, (right_hand.shape[1], right_hand.shape[0]))
return aligned
# Warp left hand image to align with right hand image
aligned = cv2.warpPerspective(left_hand, M, (right_hand.shape[1], right_hand.shape[0]))
return aligned