ORB doesn't find keypoints near the edge of an image and I don't understand why. It seems worse that SIFT and SURF and I would expect the opposite.
If I understand correctly then SIFT/SURF use a 16x16 and 20x20 square block respectedly around the test-point so I would expect them not to find keypoints 8 and 10 pixels from an edge. FAST/ORB uses a circle of diameter 7 around the test-point so I expected it to find keypoints even closer to the edge, perhaps as close as 4 pixels (though I think the associated algorithm, BRIEF, to describe keypoints uses a larger window so this would remove some keypoints).
An experiment makes nonsense of my prediction. The minimum distance from the edge in my experiments vary with the size and spacing of the squares but examples are
- SIFT .. 5 pixels
- SURF .. 15 pixels
- ORB .. 39 pixels
Can anyone explain why?
The code I used is below. I drew a grid of squares and applied a Gaussian blur. I expected the algorithms to latch onto the corners but they found the centres of the squares and some artifacts.
import numpy as np
import cv2
size = 501; border = 51; step = 10
image = np.zeros( (size,size), np.uint8 )
# fill with disjoint squares
def drawsquare(img,i,j):
restsize = step//5
cv2.rectangle(img,(i-restsize,j-restsize),(i+restsize,j+restsize),255,-1)
for i in range(0,size,step):
for j in range(0,size,step):
drawsquare(image,i,j)
# blank out the middle
image[border:size-border,border:size-border] = 0
# and blur
image = cv2.GaussianBlur(image,(5,5),0)
imgcopy = image.copy()
descriptor = cv2.xfeatures2d.SIFT_create(nfeatures=2000)
kps = descriptor.detect(image)
minpt = min([p for k in kps for p in k.pt ])
print("#{} SIFT keypoints, min coord is {} ".format(len(kps),minpt))
imgcopy = cv2.drawKeypoints(imgcopy,kps,imgcopy,(0,0,255))
cv2.imshow( "SIFT(red)", imgcopy )
cv2.waitKey()
descriptor = cv2.xfeatures2d.SURF_create()
kps, descs = descriptor.detectAndCompute(image,None)
minpt = min([p for k in kps for p in k.pt ])
print("#{} SURF keypoints , min coord is {}".format(len(kps),minpt))
imgcopy = cv2.drawKeypoints(imgcopy,kps,imgcopy,(0,255,255))
cv2.imshow( "SIFT(red)+SURF(yellow)", imgcopy )
cv2.waitKey()
descriptor = cv2.ORB_create(nfeatures=800)
kps = descriptor.detect(image)
minpt = min([p for k in kps for p in k.pt ])
print("#{} ORB keypoints, min coord is {} ".format(len(kps),minpt))
imgcopy = cv2.drawKeypoints(imgcopy,kps,imgcopy,(0,255,0))
cv2.imshow( "SIFT(red)+SURF(yellow)+ORB-detect(green)", imgcopy )
cv2.waitKey()
kps, descs = descriptor.compute(image,kps)
minpt = min([k.pt[0] for k in kps]+[k.pt[1] for k in kps])
print("#{} ORB described keypoints, min coord is {} ".format(len(kps),minpt))
imgcopy = cv2.drawKeypoints(imgcopy,kps,imgcopy,(255,0,0))
cv2.imshow( "SIFT(red)+SURF(yelow)+ORB-compute(blue)", imgcopy )
cv2.waitKey()
cv2.imwrite("/tmp/grid-with-keypoints.png",imgcopy)
Output of program is
#2000 SIFT keypoints, min coord is 5.140756607055664
#1780 SURF keypoints , min coord is 15.0
#592 ORB keypoints, min coord is 39.60000228881836
#592 ORB described keypoints, min coord is 39.60000228881836
and the image is
Addendum
Grillteller answered my question and gave me an extra parameter in the creation-code for an ORB detector. If I write
descriptor = cv2.ORB_create(nfeatures=800,edgeThreshold=0)
then I get output
#950 ORB keypoints, min coord is 9.953282356262207