SIFT
ORB
python
import copy
import time
import cv2
import numpy as np
def draw_kpts(image0, image1, mkpts0, mkpts1, margin=10):
H0, W0 = image0.shape
H1, W1 = image1.shape
H, W = max(H0, H1), W0 + W1 + margin
out = 255 * np.ones((H, W), np.uint8)
out[:H0, :W0] = image0
out[:H1, W0+margin:] = image1
out = np.stack([out]*3, -1)
mkpts0, mkpts1 = np.round(mkpts0).astype(int), np.round(mkpts1).astype(int)
# print(f"mkpts0.shape : {mkpts0.shape}")
c = (0, 255, 0)
for (new, old) in zip(mkpts0, mkpts1):
x0, y0 = new.ravel()
x1, y1 = old.ravel()
# print(f"x0 : {x0}")
# cv2.line(out, (x0, y0), (x1 + margin + W0, y1),
# color=c, thickness=1, lineType=cv2.LINE_AA)
# display line end-points as circles
cv2.circle(out, (x0, y0), 2, c, -1, lineType=cv2.LINE_AA)
cv2.circle(out, (x1 + margin + W0, y1), 2, c, -1,
lineType=cv2.LINE_AA)
return out
if __name__ == "__main__":
img0Path = "/training/datasets/orchard/orchard_imgs_/000130.jpg"
img1Path = "/training/datasets/orchard/orchard_imgs_/000132.jpg"
img0 = cv2.imread(img0Path, 0)
img1 = cv2.imread(img1Path, 0)
h, w = img0.shape
mask = np.zeros_like(img0)
mask[int(0.02 * h): int(0.98 * h), int(0.02 * w): int(0.98 * w)] = 255
feature_detector_threshold = 20
matcher_norm_type = cv2.NORM_HAMMING
# detector = cv2.FastFeatureDetector_create(threshold=feature_detector_threshold)
# extractor = cv2.ORB_create()
# matcher = cv2.BFMatcher(matcher_norm_type)
detector = cv2.SIFT_create(nOctaveLayers=3, contrastThreshold=0.02, edgeThreshold=20)
extractor = cv2.SIFT_create(nOctaveLayers=3, contrastThreshold=0.02, edgeThreshold=20)
matcher = cv2.BFMatcher(cv2.NORM_L2)
# find static keypoints
prev_keypoints = detector.detect(img0, mask)
keypoints = detector.detect(img1, mask)
# compute the descriptors
prev_keypoints, prev_descriptors = extractor.compute(img0, prev_keypoints)
keypoints, descriptors = extractor.compute(img1, keypoints)
# Match descriptors.
knnMatches = matcher.knnMatch(prev_descriptors, descriptors, k=2)
# filtered matches based on smallest spatial distance
matches = []
spatial_distances = []
max_spatial_distance = 0.25 * np.array([w, h])
for m, n in knnMatches:
if m.distance < 0.9 * n.distance:
prevKeyPointLocation = prev_keypoints[m.queryIdx].pt
currKeyPointLocation = keypoints[m.trainIdx].pt
spatial_distance = (prevKeyPointLocation[0] - currKeyPointLocation[0],
prevKeyPointLocation[1] - currKeyPointLocation[1])
if (np.abs(spatial_distance[0]) < max_spatial_distance[0]) and \
(np.abs(spatial_distance[1]) < max_spatial_distance[1]):
spatial_distances.append(spatial_distance)
matches.append(m)
mean_spatial_distances = np.mean(spatial_distances, 0)
std_spatial_distances = np.std(spatial_distances, 0)
inliesrs = (spatial_distances - mean_spatial_distances) < 2.5 * std_spatial_distances
goodMatches = []
prevPoints = []
currPoints = []
for i in range(len(matches)):
if inliesrs[i, 0] and inliesrs[i, 1]:
goodMatches.append(matches[i])
prevPoints.append(prev_keypoints[matches[i].queryIdx].pt)
currPoints.append(keypoints[matches[i].trainIdx].pt)
prevPoints = np.array(prevPoints)
currPoints = np.array(currPoints)
# find rigid matrix
if (np.size(prevPoints, 0) > 4) and (np.size(prevPoints, 0) == np.size(prevPoints, 0)):
H, inliesrs = cv2.estimateAffinePartial2D(prevPoints, currPoints, cv2.RANSAC)
else:
print('Warning: not enough matching points')
print(f"H : {H}")
out = draw_kpts(img0, img1, prevPoints, currPoints)
cv2.imwrite("keypoints.jpg", out)