{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"SITF (Scale-invariant feature transform) algorithm was proposed by David G. Rowe in 1999 and improved in 2004. Download the paper from:  \nhttps://www.cs.ubc.ca/~lowe/keypoints/","metadata":{}},{"cell_type":"markdown","source":"Lowe introduced the concept of scale into the SIFT algorithm. The essence of using SIFT method to detect image feature points is to find feature points on different scale Spaces, and these feature points correspond to ground objects of different sizes. The SIFT registration method is mainly divided into the following steps:\n\n* 1.Establishment of DOG scale space.\n* 2.Key points are extracted from the scale space.\n* 3.Generate feature descriptors.\n* 4.feature point matching.\n* 5.After that, subsequent registration processes, such as transformation model solving and resampling, can be carried out.","metadata":{}},{"cell_type":"code","source":"import cv2\nimport time\nimport matplotlib.image as mpimg\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:11:57.046102Z","iopub.execute_input":"2023-04-23T16:11:57.047105Z","iopub.status.idle":"2023-04-23T16:11:57.055079Z","shell.execute_reply.started":"2023-04-23T16:11:57.047031Z","shell.execute_reply":"2023-04-23T16:11:57.053284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image1 = mpimg.imread(\"/kaggle/input/images/1.jpg\")\nimage2 = mpimg.imread(\"/kaggle/input/images/2.jpg\")\n\nplt.figure()\nplt.imshow(image1)\n\nplt.figure()\nplt.imshow(image2)\n","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:11:57.057594Z","iopub.execute_input":"2023-04-23T16:11:57.058187Z","iopub.status.idle":"2023-04-23T16:11:58.570498Z","shell.execute_reply.started":"2023-04-23T16:11:57.058149Z","shell.execute_reply":"2023-04-23T16:11:58.569293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Feature point extraction & description generation","metadata":{}},{"cell_type":"code","source":"#  Calculate the feature point extraction & generation description time\nstart = time.time()\nsift = cv2.SIFT_create()\n#  Use SIFT to find key points and descriptors\nkp1, des1 = sift.detectAndCompute(image1, None)\nkp2, des2 = sift.detectAndCompute(image2, None)\nend = time.time()\nprint(\"Feature Point Extraction & Generation description running time:%.2fseconds\"%(end-start))\n\nkp_image1 = cv2.drawKeypoints(image1, kp1, None)\nkp_image2 = cv2.drawKeypoints(image2, kp2, None)\n\nplt.figure()\nplt.imshow(kp_image1)\n#plt.savefig('kp_image1.png', dpi = 300)\n\nplt.figure()\nplt.imshow(kp_image2)\n#plt.savefig('kp_image2.png', dpi = 300)","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:11:58.572002Z","iopub.execute_input":"2023-04-23T16:11:58.572347Z","iopub.status.idle":"2023-04-23T16:12:01.980302Z","shell.execute_reply.started":"2023-04-23T16:11:58.572314Z","shell.execute_reply":"2023-04-23T16:12:01.978738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#  View key points\nprint(\"Number of key points:\", len(kp1))\n\nfor i in range(2):\n    print(\"key point\", i)\n    print(\"data type:\", type(kp1[i]))\n    print(\"Key point coordinates:\", kp1[i].pt)\n    print(\"Neighborhood diameter:\", kp1[i].size)\n    print(\"direction:\", kp1[i].angle)\n    print(\"In the image pyramid group:\", kp1[i].octave)\n    print(\"================\")\n\n#  View Description\nprint(\"description shape:\", des1.shape)\nfor i in range(2):\n    print(\"Description\", i)\n    print(des1[i])","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:12:01.981963Z","iopub.execute_input":"2023-04-23T16:12:01.982279Z","iopub.status.idle":"2023-04-23T16:12:01.995239Z","shell.execute_reply.started":"2023-04-23T16:12:01.982249Z","shell.execute_reply":"2023-04-23T16:12:01.993869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  Draw the correspondence","metadata":{}},{"cell_type":"code","source":"ratio = 0.85\n\n#  Calculate the matching time of matching points\nstart = time.time()\n\n#  The k-nearest neighbors algorithm finds the K nearest data points in space and groups them together\nmatcher = cv2.BFMatcher()\nraw_matches = matcher.knnMatch(des1, des2, k = 2)\ngood_matches = []\nfor m1, m2 in raw_matches:\n    #  If the ratio of the closest point to the next closest point is greater than a given value, we keep the closest point and consider it and its matching point good_match\n    if m1.distance < ratio * m2.distance:\n        good_matches.append([m1])\nend = time.time()\nprint(\"The matching point matches the running time:%.2fseconds\"%(end-start))\n\n\nmatches = cv2.drawMatchesKnn(image1, kp1, image2, kp2, good_matches, None, flags = 2)\n\nplt.figure()\nplt.imshow(matches)\nplt.savefig('matches.png', dpi = 300)","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:12:01.999204Z","iopub.execute_input":"2023-04-23T16:12:01.999672Z","iopub.status.idle":"2023-04-23T16:12:06.091533Z","shell.execute_reply.started":"2023-04-23T16:12:01.999631Z","shell.execute_reply":"2023-04-23T16:12:06.089888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# The number of matching pairs","metadata":{}},{"cell_type":"code","source":"print(\"The number of matching pairs:\", len(good_matches))\nfor i in range(2):\n    print(\"matching\", i)\n    print(\"data type:\", type(good_matches[i][0]))\n    print(\"The distance between descriptors:\", good_matches[i][0].distance)\n    print(\"Queries the index of descriptors in an image:\", good_matches[i][0].queryIdx)\n    print(\"Index of descriptors in the target image:\", good_matches[i][0].trainIdx)\n    print(\"================\")","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:12:06.093291Z","iopub.execute_input":"2023-04-23T16:12:06.093773Z","iopub.status.idle":"2023-04-23T16:12:06.104006Z","shell.execute_reply.started":"2023-04-23T16:12:06.093733Z","shell.execute_reply":"2023-04-23T16:12:06.102324Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\n\n#  The homography matrix has eight parameters, and each corresponding pixel can generate two equations (one for x and one for y), so it takes four pixels to solve the homography matrix\nif len(good_matches) > 4:\n    #  Calculated matching time\n    start = time.time()\n    ptsA= np.float32([kp1[m[0].queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)\n    ptsB = np.float32([kp2[m[0].trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)\n    ransacReprojThreshold = 4\n    #  A homologous matrix can align one graph with another by rotation, transformation, etc\n    H, status =cv2.findHomography(ptsA,ptsB,cv2.RANSAC,ransacReprojThreshold);\n    imgOut = cv2.warpPerspective(image2, H, (image1.shape[1],image1.shape[0]),flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)\n    end = time.time()\n    print(\"Matching running time:%.2fseconds\"%(end-start))\n    \n    plt.figure()\n    plt.imshow(image1)\n    plt.figure()\n    plt.imshow(image2)\n    plt.figure()\n    plt.imshow(imgOut)\n    plt.savefig('imgOut.png', dpi = 300)","metadata":{"execution":{"iopub.status.busy":"2023-04-23T16:12:06.105340Z","iopub.execute_input":"2023-04-23T16:12:06.105750Z","iopub.status.idle":"2023-04-23T16:12:09.717551Z","shell.execute_reply.started":"2023-04-23T16:12:06.105714Z","shell.execute_reply":"2023-04-23T16:12:09.716274Z"},"trusted":true},"execution_count":null,"outputs":[]}]}