0

I wanna make a function that match keypoints of two of images by use Python. And here is important thing: I don't wanna use built-in function except what's included in mine. I used two of same images, but second one is rotated 90 degree.

enter image description here

...

def mySIFT(src):
    gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY).astype(np.float32)

    dst = cv2.cornerHarris(gray, 3, 3, 0.04)
    dst[dst < 0.01 * dst.max()] = 0
    dst = find_local_maxima(dst, 21)
    dst = dst / dst.max()

    y, x = np.nonzero(dst)

    keypoints = []
    for i in range(len(x)):
        pt_x = int(x[i])
        pt_y = int(y[i])
        response = dst[y[i], x[i]]
        keypoints.append(KeyPoint(pt_x, pt_y, None, -1, response, 0, -1))
        
    Ix, Iy = calc_derivatives(gray)

    magnitude = np.sqrt(Ix ** 2 + Iy ** 2)
    angle = np.rad2deg(np.arctan2(Iy, Ix))
    angle = (angle + 360) % 360

    num = 0
    for i in range(len(keypoints)):
        x, y = keypoints[i].pt
        orient_hist = np.zeros(36, )
        for row in range(-8, 8):
            for col in range(-8, 8):
                p_y = int(y + row)
                p_x = int(x + col)
                if p_y < 0 or p_y > src.shape[0] - 1 or p_x < 0 or p_x > src.shape[1] - 1:
                    continue
                gaussian_weight = np.exp((-1 / 16) * (row ** 2 + col ** 2))
                orient_hist[int(angle[p_y, p_x] // 10)] += magnitude[p_y, p_x] * gaussian_weight
       
        keypoints[i].angle = np.max(orient_hist)
        
        for ori in range(len(orient_hist)):
            if orient_hist[ori] > 0.75 * keypoints[i].angle:
                if ori != np.argmax(orient_hist):
                    keypoints.append(KeyPoint (pt_x, pt_y, size, orient_hist[ori], keypoints[i].response, 0, -1))
    
    descriptors = np.zeros((len(keypoints), 128))

    for i in range(len(keypoints)):
        x, y = keypoints[i].pt
        theta = np.deg2rad(keypoints[i].angle)
        cos_angle = np.cos(theta)
        sin_angle = np.sin(theta)
        
        for row in range(-8, 8):
            for col in range(-8, 8):
                row_rot = np.round((cos_angle * col) + (sin_angle * row))
                col_rot = np.round((cos_angle * col) - (sin_angle * row))

                p_y = int(y + row_rot)
                p_x = int(x + col_rot)
                if p_y < 0 or p_y > (src.shape[0] - 1) or p_x < 0 or p_x > (src.shape[1] - 1):
                    continue
                
                descriptor_angle = angle[p_y, p_x] - keypoints[i].angle

                while descriptor_angle < 0.0:
                    descriptor_angle += 360.0
                while descriptor_angle >= 360.0:
                    descriptor_angle -= 360.0
                descriptor_angle = math.floor(descriptor_angle / 45)
                
                new_row = 2 + math.floor(row / 4)
                new_col = 2 + math.floor(col / 4)
               
                new_num = 8 * (new_col * 4 + new_row)
                
                descriptors[i, new_num + descriptor_angle] += magnitude[p_y, p_x] * gaussian_weight

    return keypoints, descriptors


def main():
    src = cv2.imread("font.png")
    src_rotation = cv2.rotate(src, cv2.ROTATE_90_CLOCKWISE)

    kp1, des1 = mySIFT(src)
    kp2, des2 = mySIFT(src_rotation)
    
    bf = cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheck=True)
    des1 = des1.astype(np.uint8)
    des2 = des2.astype(np.uint8)
    matches = bf.match(des1, des2)
    matches = sorted(matches, key=lambda x: x.distance)

    result = cv2.drawMatches(src, kp1, src_rotation, kp2, matches[:20], outImg=None, flags=2)

    cv2.imshow('sift', result)
    cv2.waitKey()
    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

Specifically, it can find all of keypoints correctly, but it match wrong keypoints. When I use two perfectly same images(rotations are same), my program will work. However, if one of image is rotated, it cannot match.

There are two line that I think there are error:

keypoints.append(KeyPoint (pt_x, pt_y, size, orient_hist[ori], keypoints[i].response, 0, -1))

This line will try to append new keypoints in array, because I wanna add all of weights that is greater than 80% of most huge weight. I thought my problems are wrong parameters, so I checked it, but I could not solve.

descriptors[i, new_num + descriptor_angle] += magnitude[p_y, p_x] * gaussian_weight

This one will save data of magnitude reflected by gaussian weight. I thought I wrote wrong formula, but I don't know what is the right one(including mine).

I cannot find the problem, so is there anyone can help me?

0 Answers0