{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":91498,"databundleVersionId":11655853,"sourceType":"competition"}],"dockerImageVersionId":31011,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\n#import os\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:00:35.531856Z","iopub.execute_input":"2025-04-17T11:00:35.532096Z","iopub.status.idle":"2025-04-17T11:00:36.506477Z","shell.execute_reply.started":"2025-04-17T11:00:35.532073Z","shell.execute_reply":"2025-04-17T11:00:36.505689Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom sklearn.cluster import DBSCAN  # Used for scene grouping based on feature similarity\nfrom collections import defaultdict\nfrom sklearn.metrics import pairwise_distances\nfrom scipy.spatial.transform import Rotation as R  # For pose estimation","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:00:54.459966Z","iopub.execute_input":"2025-04-17T11:00:54.460483Z","iopub.status.idle":"2025-04-17T11:00:55.981458Z","shell.execute_reply.started":"2025-04-17T11:00:54.460455Z","shell.execute_reply":"2025-04-17T11:00:55.980707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load the data\ntrain_path = \"../input/image-matching-challenge-2025/train\"\ntrain_labels = pd.read_csv('/kaggle/input/image-matching-challenge-2025/train_labels.csv')\ntrain_thresholds = pd.read_csv(\"/kaggle/input/image-matching-challenge-2025/train_thresholds.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:01:18.810442Z","iopub.execute_input":"2025-04-17T11:01:18.810961Z","iopub.status.idle":"2025-04-17T11:01:18.862835Z","shell.execute_reply.started":"2025-04-17T11:01:18.810920Z","shell.execute_reply":"2025-04-17T11:01:18.862071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def extract_features(image_path):\n    image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n    sift = cv2.SIFT_create()  # can be switch to SuperPoint or DELF for better results\n    kp, des = sift.detectAndCompute(image, None)\n    return kp, des","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:01:52.124607Z","iopub.execute_input":"2025-04-17T11:01:52.125137Z","iopub.status.idle":"2025-04-17T11:01:52.128978Z","shell.execute_reply.started":"2025-04-17T11:01:52.125115Z","shell.execute_reply":"2025-04-17T11:01:52.128172Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Loading images for a specific scene\nscene_name = \"fountain\"\nscene_images = train_labels[train_labels[\"scene\"] == scene_name][\"image\"].values\n\n# Feature extraction and clustering images by similarity\nfeatures = []\nimage_paths = []\n\nfor img_name in scene_images:\n    img_path = os.path.join(train_path, train_labels[train_labels[\"scene\"] == scene_name][\"dataset\"].values[0], img_name)\n    kp, des = extract_features(img_path)\n    features.append(des)\n    image_paths.append(img_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:03:02.550128Z","iopub.execute_input":"2025-04-17T11:03:02.550874Z","iopub.status.idle":"2025-04-17T11:03:42.537779Z","shell.execute_reply.started":"2025-04-17T11:03:02.550847Z","shell.execute_reply":"2025-04-17T11:03:42.537211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Matching images using pairwise distances between descriptors (can be optimize with FLANN or nearest neighbor search)\ndist_matrix = pairwise_distances([np.mean(f, axis=0) for f in features], metric=\"cosine\")\n\n# Grouping images into scenes using DBSCAN\nclustering = DBSCAN(eps=0.5, min_samples=3, metric=\"precomputed\").fit(dist_matrix)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:03:47.579480Z","iopub.execute_input":"2025-04-17T11:03:47.579774Z","iopub.status.idle":"2025-04-17T11:03:47.684269Z","shell.execute_reply.started":"2025-04-17T11:03:47.579752Z","shell.execute_reply":"2025-04-17T11:03:47.683761Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Visualizing clusters\nscene_groups = defaultdict(list)\nfor idx, label in enumerate(clustering.labels_):\n    scene_groups[label].append(image_paths[idx])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:04:08.804195Z","iopub.execute_input":"2025-04-17T11:04:08.804800Z","iopub.status.idle":"2025-04-17T11:04:08.808514Z","shell.execute_reply.started":"2025-04-17T11:04:08.804778Z","shell.execute_reply":"2025-04-17T11:04:08.807850Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Seeing clustered images from the same scene\nfig, axes = plt.subplots(1, len(scene_groups[0]), figsize=(15, 10))\nfor i, img_path in enumerate(scene_groups[0]):  # Display first group\n    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n    axes[i].imshow(img, cmap='gray')\n    axes[i].axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:04:36.534563Z","iopub.execute_input":"2025-04-17T11:04:36.534840Z","iopub.status.idle":"2025-04-17T11:04:40.195263Z","shell.execute_reply.started":"2025-04-17T11:04:36.534822Z","shell.execute_reply":"2025-04-17T11:04:40.194517Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# For camera pose estimation using essential matrix(RANSAC)\ndef estimate_camera_pose(kp1, kp2, des1, des2):\n    # Matcher\n    bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)\n    matches = bf.match(des1, des2)\n    \n    # Keypoints\n    src_pts = np.float32([kp1[m.queryIdx].pt for m in matches]).reshape(-1, 1, 2)\n    dst_pts = np.float32([kp2[m.trainIdx].pt for m in matches]).reshape(-1, 1, 2)\n    \n    # Essential matrix and pose recovery\n    E, mask = cv2.findEssentialMat(src_pts, dst_pts, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n    _, R_mat, t_vec, mask = cv2.recoverPose(E, src_pts, dst_pts)\n    \n    return R_mat, t_vec","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:05:57.910046Z","iopub.execute_input":"2025-04-17T11:05:57.910317Z","iopub.status.idle":"2025-04-17T11:05:57.915722Z","shell.execute_reply.started":"2025-04-17T11:05:57.910298Z","shell.execute_reply":"2025-04-17T11:05:57.914995Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# matching two images from the same scene and estimate pose\nimg1_path = scene_groups[0][0]  # Choose first image in the group\nimg2_path = scene_groups[0][1]  # Choose another image in the group\n\n# Extracting keypoints and descriptors\nkp1, des1 = extract_features(img1_path)\nkp2, des2 = extract_features(img2_path)\n\n# Estimating camera pose between two images\nR_mat, t_vec = estimate_camera_pose(kp1, kp2, des1, des2)\n\n# Visualizing rotation and translation\nprint(f\"Rotation Matrix:\\n{R_mat}\")\nprint(f\"Translation Vector:\\n{t_vec}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:06:36.634449Z","iopub.execute_input":"2025-04-17T11:06:36.635029Z","iopub.status.idle":"2025-04-17T11:07:07.266804Z","shell.execute_reply.started":"2025-04-17T11:06:36.635007Z","shell.execute_reply":"2025-04-17T11:07:07.265938Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_submission = pd.read_csv('/kaggle/input/image-matching-challenge-2025/sample_submission.csv')\nsample_submission[\"rotation_matrix\"] = \"1;0;0;0;1;0;0;0;1\"  # Placeholder\nsample_submission[\"translation_vector\"] = \"0;0;0\"  # Placeholder\n\n\nsample_submission.to_csv(\"submission.csv\", index=False)\nprint(\"Submission file created!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-17T11:07:13.900046Z","iopub.execute_input":"2025-04-17T11:07:13.900308Z","iopub.status.idle":"2025-04-17T11:07:13.941805Z","shell.execute_reply.started":"2025-04-17T11:07:13.900290Z","shell.execute_reply":"2025-04-17T11:07:13.941081Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}