{"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":"none","dataSources":[{"sourceId":91498,"databundleVersionId":11655853,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.203904Z","iopub.execute_input":"2025-06-02T21:08:59.204268Z","iopub.status.idle":"2025-06-02T21:08:59.210273Z","shell.execute_reply.started":"2025-06-02T21:08:59.204242Z","shell.execute_reply":"2025-06-02T21:08:59.208861Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Path to train_labels.csv\nlabels_path = \"/kaggle/input/image-matching-challenge-2025/train_labels.csv\"\n\n# Load the CSV into a DataFrame\ndf = pd.read_csv(labels_path)\n\n# Display first 5 rows\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.212258Z","iopub.execute_input":"2025-06-02T21:08:59.212560Z","iopub.status.idle":"2025-06-02T21:08:59.250099Z","shell.execute_reply.started":"2025-06-02T21:08:59.212538Z","shell.execute_reply":"2025-06-02T21:08:59.249107Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Count total images\nprint(\"Total images in training set:\", len(df))\n\n# Unique datasets\nprint(\"\\nUnique datasets:\")\nprint(df['dataset'].value_counts())\n\n# Unique scenes\nprint(\"\\nUnique scenes:\")\nprint(df['scene'].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.250869Z","iopub.execute_input":"2025-06-02T21:08:59.251940Z","iopub.status.idle":"2025-06-02T21:08:59.261927Z","shell.execute_reply.started":"2025-06-02T21:08:59.251903Z","shell.execute_reply":"2025-06-02T21:08:59.260748Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ek row select karo DataFrame se\nrow = df.iloc[0]\n\n# Extract values\ndataset = row['dataset']\nimage_name = row['image']\n\n# Image path banao\nimage_path = f\"/kaggle/input/image-matching-challenge-2025/train/{dataset}/{image_name}\"\nprint(\"Image path:\", image_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.263937Z","iopub.execute_input":"2025-06-02T21:08:59.264310Z","iopub.status.idle":"2025-06-02T21:08:59.281081Z","shell.execute_reply.started":"2025-06-02T21:08:59.264287Z","shell.execute_reply":"2025-06-02T21:08:59.280090Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport matplotlib.pyplot as plt\n\n# Load image in BGR format (OpenCV ka default)\nimage = cv2.imread(image_path)\n\n# Convert BGR to RGB (matplotlib sahi colors ke liye)\nimage_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n# Show image\nplt.figure(figsize=(6, 6))\nplt.imshow(image_rgb)\nplt.title(image_name)\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.282073Z","iopub.execute_input":"2025-06-02T21:08:59.282322Z","iopub.status.idle":"2025-06-02T21:08:59.892942Z","shell.execute_reply.started":"2025-06-02T21:08:59.282304Z","shell.execute_reply":"2025-06-02T21:08:59.891961Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Rotation & Translation\nrotation = row['rotation_matrix']\ntranslation = row['translation_vector']\n\nprint(\"Rotation Matrix:\", rotation)\nprint(\"Translation Vector:\", translation)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.893965Z","iopub.execute_input":"2025-06-02T21:08:59.894233Z","iopub.status.idle":"2025-06-02T21:08:59.899579Z","shell.execute_reply.started":"2025-06-02T21:08:59.894214Z","shell.execute_reply":"2025-06-02T21:08:59.898560Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Rotation & Translation Strings\nrotation_str = row['rotation_matrix']\ntranslation_str = row['translation_vector']\n\n# Convert strings to list of floats\nrotation_list = [float(x) for x in rotation_str.split(';')]\ntranslation_list = [float(x) for x in translation_str.split(';')]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.900600Z","iopub.execute_input":"2025-06-02T21:08:59.900989Z","iopub.status.idle":"2025-06-02T21:08:59.924241Z","shell.execute_reply.started":"2025-06-02T21:08:59.900967Z","shell.execute_reply":"2025-06-02T21:08:59.923166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Convert to NumPy arrays\nrotation_matrix = np.array(rotation_list).reshape((3, 3))\ntranslation_vector = np.array(translation_list).reshape((3, 1))  # column vector\n\n# Print\nprint(\"Rotation Matrix:\\n\", rotation_matrix)\nprint(\"\\nTranslation Vector:\\n\", translation_vector)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.925384Z","iopub.execute_input":"2025-06-02T21:08:59.925662Z","iopub.status.idle":"2025-06-02T21:08:59.939974Z","shell.execute_reply.started":"2025-06-02T21:08:59.925627Z","shell.execute_reply":"2025-06-02T21:08:59.938615Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Sabhi translation vectors ko extract karo\ntranslations = []\n\nfor i in range(len(df)):\n    t_str = df.iloc[i]['translation_vector']\n    t = [float(x) for x in t_str.split(';')]\n    translations.append(t)\n\n# NumPy array bana lo (shape: [num_images, 3])\ntranslations = np.array(translations)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:08:59.943083Z","iopub.execute_input":"2025-06-02T21:08:59.943394Z","iopub.status.idle":"2025-06-02T21:09:00.006250Z","shell.execute_reply.started":"2025-06-02T21:08:59.943371Z","shell.execute_reply":"2025-06-02T21:09:00.005106Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from mpl_toolkits.mplot3d import Axes3D\nimport matplotlib.pyplot as plt\n\nfig = plt.figure(figsize=(10, 8))\nax = fig.add_subplot(111, projection='3d')\n\n# Scatter plot of translations\nax.scatter(translations[:, 0], translations[:, 1], translations[:, 2], c='blue', s=5)\n\nax.set_title(\"3D Image Positions (Translation Vectors)\")\nax.set_xlabel(\"X\")\nax.set_ylabel(\"Y\")\nax.set_zlabel(\"Z\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:00.007282Z","iopub.execute_input":"2025-06-02T21:09:00.007582Z","iopub.status.idle":"2025-06-02T21:09:00.232068Z","shell.execute_reply.started":"2025-06-02T21:09:00.007556Z","shell.execute_reply":"2025-06-02T21:09:00.231208Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"camera_centers = []\ncamera_directions = []\n\nfor i in range(len(df)):\n    # Parse translation\n    t_str = df.iloc[i]['translation_vector']\n    t = np.array([float(x) for x in t_str.split(';')]).reshape((3, 1))\n    \n    # Parse rotation\n    r_str = df.iloc[i]['rotation_matrix']\n    r = np.array([float(x) for x in r_str.split(';')]).reshape((3, 3))\n    \n    # Camera center (origin)\n    camera_centers.append(t.flatten())\n    \n    # Camera direction vector (Z axis)\n    direction = r @ np.array([0, 0, 1])  # or -r[:, 2]\n    camera_directions.append(direction)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:00.232948Z","iopub.execute_input":"2025-06-02T21:09:00.233182Z","iopub.status.idle":"2025-06-02T21:09:00.391524Z","shell.execute_reply.started":"2025-06-02T21:09:00.233163Z","shell.execute_reply":"2025-06-02T21:09:00.390766Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from mpl_toolkits.mplot3d import Axes3D\nimport matplotlib.pyplot as plt\n\ncamera_centers = np.array(camera_centers)\ncamera_directions = np.array(camera_directions)\n\nfig = plt.figure(figsize=(12, 9))\nax = fig.add_subplot(111, projection='3d')\n\n# Plot camera positions\nax.scatter(camera_centers[:, 0], camera_centers[:, 1], camera_centers[:, 2], color='blue', s=5)\n\n# Plot direction arrows\nscale = 0.1  # arrow length\nfor i in range(len(camera_centers)):\n    c = camera_centers[i]\n    d = camera_directions[i]\n    ax.quiver(c[0], c[1], c[2], d[0], d[1], d[2], length=scale, color='red')\n\nax.set_title(\"Camera Orientations in 3D Space\")\nax.set_xlabel(\"X\")\nax.set_ylabel(\"Y\")\nax.set_zlabel(\"Z\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:00.392285Z","iopub.execute_input":"2025-06-02T21:09:00.392508Z","iopub.status.idle":"2025-06-02T21:09:04.064545Z","shell.execute_reply.started":"2025-06-02T21:09:00.392491Z","shell.execute_reply":"2025-06-02T21:09:04.063665Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"grouped = df.groupby(['dataset', 'scene'])\n\n# Show how many images are in each group\nfor (dataset, scene), group in grouped:\n    print(f\"{dataset} / {scene} => {len(group)} images\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.065459Z","iopub.execute_input":"2025-06-02T21:09:04.065737Z","iopub.status.idle":"2025-06-02T21:09:04.075889Z","shell.execute_reply.started":"2025-06-02T21:09:04.065716Z","shell.execute_reply":"2025-06-02T21:09:04.074963Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Outliers are usually in dataset/scene == \"unknown\" or with single images\noutlier_candidates = df.groupby(['dataset', 'scene']).filter(lambda g: len(g) <= 2)\n\nprint(f\"Possible outliers found: {len(outlier_candidates)}\")\ndisplay(outlier_candidates.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.076753Z","iopub.execute_input":"2025-06-02T21:09:04.077022Z","iopub.status.idle":"2025-06-02T21:09:04.097941Z","shell.execute_reply.started":"2025-06-02T21:09:04.077000Z","shell.execute_reply":"2025-06-02T21:09:04.097079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nfolder_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond'\nimage_files = os.listdir(folder_path)\n\nprint(\"Available image files:\", image_files[:10])  # First 10 filenames","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.098846Z","iopub.execute_input":"2025-06-02T21:09:04.099156Z","iopub.status.idle":"2025-06-02T21:09:04.105363Z","shell.execute_reply.started":"2025-06-02T21:09:04.099129Z","shell.execute_reply":"2025-06-02T21:09:04.104441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img1_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/lizard_image_0003.png'\nimg2_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/lizard_image_0007.png'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.106237Z","iopub.execute_input":"2025-06-02T21:09:04.106477Z","iopub.status.idle":"2025-06-02T21:09:04.121913Z","shell.execute_reply.started":"2025-06-02T21:09:04.106460Z","shell.execute_reply":"2025-06-02T21:09:04.120760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img1_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/pond_image_0012.png'\nimg2_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/pond_image_0021.png'\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.122881Z","iopub.execute_input":"2025-06-02T21:09:04.123162Z","iopub.status.idle":"2025-06-02T21:09:04.139138Z","shell.execute_reply.started":"2025-06-02T21:09:04.123143Z","shell.execute_reply":"2025-06-02T21:09:04.138211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nbase_path = \"/kaggle/input/image-matching-challenge-2025/train\"\n\nprint(\"Datasets available in /train:\")\nprint(os.listdir(base_path))\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.140208Z","iopub.execute_input":"2025-06-02T21:09:04.140526Z","iopub.status.idle":"2025-06-02T21:09:04.156506Z","shell.execute_reply.started":"2025-06-02T21:09:04.140501Z","shell.execute_reply":"2025-06-02T21:09:04.155795Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folder_path = base_path + \"/imc2024_lizard_pond\"\nprint(\"Files in imc2024_lizard_pond:\")\nprint(os.listdir(folder_path)[:10])  # First 10 files\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.157717Z","iopub.execute_input":"2025-06-02T21:09:04.158022Z","iopub.status.idle":"2025-06-02T21:09:04.173432Z","shell.execute_reply.started":"2025-06-02T21:09:04.157984Z","shell.execute_reply":"2025-06-02T21:09:04.172453Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nfolder_path = \"/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond\"\n\n# List actual files in the folder\nfiles = os.listdir(folder_path)\nprint(\"Total files:\", len(files))\nprint(\"First 20 files:\")\nfor f in files[:20]:\n    print(f)\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.174322Z","iopub.execute_input":"2025-06-02T21:09:04.174635Z","iopub.status.idle":"2025-06-02T21:09:04.198019Z","shell.execute_reply.started":"2025-06-02T21:09:04.174607Z","shell.execute_reply":"2025-06-02T21:09:04.197157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport matplotlib.pyplot as plt\n\nimg1_path = \"/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/lizard_00003.png\"\nimg2_path = \"/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/lizard_00361.png\"\n\n# Load grayscale\nimg1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)\nimg2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)\n\n# Show images\nplt.figure(figsize=(12, 6))\nplt.subplot(1, 2, 1)\nplt.imshow(img1, cmap='gray')\nplt.title(\"Image 1\")\nplt.axis('off')\n\nplt.subplot(1, 2, 2)\nplt.imshow(img2, cmap='gray')\nplt.title(\"Image 2\")\nplt.axis('off')\n\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.199029Z","iopub.execute_input":"2025-06-02T21:09:04.199279Z","iopub.status.idle":"2025-06-02T21:09:04.772202Z","shell.execute_reply.started":"2025-06-02T21:09:04.199259Z","shell.execute_reply":"2025-06-02T21:09:04.771123Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport matplotlib.pyplot as plt\n\n# Initialize SIFT detector\nsift = cv2.SIFT_create()\n\n# Detect keypoints and descriptors\nkp1, des1 = sift.detectAndCompute(img1, None)\nkp2, des2 = sift.detectAndCompute(img2, None)\n\n# BFMatcher with default params\nbf = cv2.BFMatcher()\nmatches = bf.knnMatch(des1, des2, k=2)\n\n# Apply ratio test (Lowe's ratio test)\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.75 * n.distance:\n        good_matches.append(m)\n\n# Draw top 50 matches\nmatched_img = cv2.drawMatches(img1, kp1, img2, kp2, good_matches[:50], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)\n\n# Show the matches\nplt.figure(figsize=(20, 10))\nplt.imshow(matched_img)\nplt.title(\"Top 50 Feature Matches\")\nplt.axis('off')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:04.773201Z","iopub.execute_input":"2025-06-02T21:09:04.773493Z","iopub.status.idle":"2025-06-02T21:09:05.842801Z","shell.execute_reply.started":"2025-06-02T21:09:04.773471Z","shell.execute_reply":"2025-06-02T21:09:05.841516Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\n# Convert keypoints to coordinates\npts1 = np.float32([kp1[m.queryIdx].pt for m in good_matches])\npts2 = np.float32([kp2[m.trainIdx].pt for m in good_matches])\n\n# Assume fx = fy = 1, cx = cy = 0 (normalized coords) – or use real intrinsics if available\nK = np.eye(3)  # identity intrinsic matrix (you can replace this later with real intrinsics)\n\n# Estimate Essential Matrix\nE, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n\n# Recover relative pose from Essential Matrix\n_, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\n\nprint(\"Rotation Matrix (R):\\n\", R)\nprint(\"Translation Vector (t):\\n\", t)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:05.843918Z","iopub.execute_input":"2025-06-02T21:09:05.844180Z","iopub.status.idle":"2025-06-02T21:09:05.884747Z","shell.execute_reply.started":"2025-06-02T21:09:05.844160Z","shell.execute_reply":"2025-06-02T21:09:05.883941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Original matches:\", len(matches))\nprint(\"Inliers found by RANSAC:\", np.sum(mask))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:05.890747Z","iopub.execute_input":"2025-06-02T21:09:05.891530Z","iopub.status.idle":"2025-06-02T21:09:05.895902Z","shell.execute_reply.started":"2025-06-02T21:09:05.891506Z","shell.execute_reply":"2025-06-02T21:09:05.894977Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, threshold=2.0, prob=0.999)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:05.896802Z","iopub.execute_input":"2025-06-02T21:09:05.897019Z","iopub.status.idle":"2025-06-02T21:09:05.946048Z","shell.execute_reply.started":"2025-06-02T21:09:05.897003Z","shell.execute_reply":"2025-06-02T21:09:05.944903Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\n\n# Load grayscale images\nimg1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)\nimg2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)\n\n# Check they loaded properly\nif img1 is None or img2 is None:\n    raise ValueError(\"Images couldn't be loaded. Check file paths.\")\n\n# Create SIFT detector\nsift = cv2.SIFT_create()\n\n# Detect and compute descriptors\nkp1, desc1 = sift.detectAndCompute(img1, None)\nkp2, desc2 = sift.detectAndCompute(img2, None)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:05.947028Z","iopub.execute_input":"2025-06-02T21:09:05.947255Z","iopub.status.idle":"2025-06-02T21:09:06.412442Z","shell.execute_reply.started":"2025-06-02T21:09:05.947237Z","shell.execute_reply":"2025-06-02T21:09:06.411530Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Matcher\nbf = cv2.BFMatcher()\nmatches = bf.knnMatch(desc1, desc2, k=2)\n\n# Lowe's ratio test\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.75 * n.distance:\n        good_matches.append(m)\n\nprint(\"Good matches:\", len(good_matches))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:06.413370Z","iopub.execute_input":"2025-06-02T21:09:06.414073Z","iopub.status.idle":"2025-06-02T21:09:06.459219Z","shell.execute_reply.started":"2025-06-02T21:09:06.414049Z","shell.execute_reply":"2025-06-02T21:09:06.458248Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Lowe's ratio test\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.8 * n.distance:  # pehle 0.75 tha\n        good_matches.append(m)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:06.460176Z","iopub.execute_input":"2025-06-02T21:09:06.460412Z","iopub.status.idle":"2025-06-02T21:09:06.466004Z","shell.execute_reply.started":"2025-06-02T21:09:06.460394Z","shell.execute_reply":"2025-06-02T21:09:06.465023Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Total good matches:\", len(good_matches))\nif len(good_matches) < 8:\n    print(\" Not enough matches for pose estimation.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:06.466840Z","iopub.execute_input":"2025-06-02T21:09:06.467087Z","iopub.status.idle":"2025-06-02T21:09:06.481075Z","shell.execute_reply.started":"2025-06-02T21:09:06.467062Z","shell.execute_reply":"2025-06-02T21:09:06.480200Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_matches = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, flags=2)\nplt.figure(figsize=(15, 10))\nplt.imshow(img_matches)\nplt.title(\"Feature Matches\")\nplt.axis('off')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:06.482316Z","iopub.execute_input":"2025-06-02T21:09:06.482601Z","iopub.status.idle":"2025-06-02T21:09:07.136400Z","shell.execute_reply.started":"2025-06-02T21:09:06.482576Z","shell.execute_reply":"2025-06-02T21:09:07.135429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img1_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/lizard_00361.png'\nimg2_path = '/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond/lizard_00527.png'\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:07.137494Z","iopub.execute_input":"2025-06-02T21:09:07.137783Z","iopub.status.idle":"2025-06-02T21:09:07.142444Z","shell.execute_reply.started":"2025-06-02T21:09:07.137763Z","shell.execute_reply":"2025-06-02T21:09:07.141541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"orb = cv2.ORB_create(1000)\nkp1, desc1 = orb.detectAndCompute(img1, None)\nkp2, desc2 = orb.detectAndCompute(img2, None)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:07.143516Z","iopub.execute_input":"2025-06-02T21:09:07.143835Z","iopub.status.idle":"2025-06-02T21:09:07.194871Z","shell.execute_reply.started":"2025-06-02T21:09:07.143806Z","shell.execute_reply":"2025-06-02T21:09:07.193963Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"desc1: {desc1 is not None}, shape: {desc1.shape if desc1 is not None else 'None'}\")\nprint(f\"desc2: {desc2 is not None}, shape: {desc2.shape if desc2 is not None else 'None'}\")\nprint(f\"Keypoints in img1: {len(kp1)}, img2: {len(kp2)}\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:07.195809Z","iopub.execute_input":"2025-06-02T21:09:07.196068Z","iopub.status.idle":"2025-06-02T21:09:07.201709Z","shell.execute_reply.started":"2025-06-02T21:09:07.196048Z","shell.execute_reply":"2025-06-02T21:09:07.200830Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if desc1 is not None and desc2 is not None:\n    matches = bf.knnMatch(desc1, desc2, k=2)\n\n    good_matches = []\n    for m, n in matches:\n        if m.distance < 0.75 * n.distance:\n            good_matches.append(m)\n\n    print(f\"Good matches found: {len(good_matches)}\")\n\n    if len(good_matches) > 0:\n        img_matches = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None, flags=2)\n        plt.figure(figsize=(15, 10))\n        plt.imshow(img_matches)\n        plt.title(\"Good Matches\")\n        plt.axis('off')\n        plt.show()\n    else:\n        print(\" No good matches to display.\")\nelse:\n    print(\" One or both descriptors are None. Skipping matching.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-02T21:09:07.202955Z","iopub.execute_input":"2025-06-02T21:09:07.203256Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Extract matched keypoints\npts1 = np.float32([kp1[m.queryIdx].pt for m in good_matches])\npts2 = np.float32([kp2[m.trainIdx].pt for m in good_matches])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Temporary guess — replace this with real intrinsics from dataset!\nfx = fy = 1000  # Focal length in pixels\ncx = 512        # Principal point x (assuming image size ~1024x768)\ncy = 384        # Principal point y\n\nK = np.array([[fx, 0, cx],\n              [0, fy, cy],\n              [0,  0,  1]])","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nbase_path = \"/kaggle/input/image-matching-challenge-2025/train/imc2024_lizard_pond\"\n\nfor root, dirs, files in os.walk(base_path):\n    print(f\" Directory: {root}\")\n    for file in files:\n        print(f\"    🗎 {file}\")\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fx = 1600 * 0.8  # Focal length in x (assume 80% of width)\nfy = 1200 * 0.8  # Focal length in y (assume 80% of height)\ncx = 1600 / 2    # Principal point x (center of image)\ncy = 1200 / 2    # Principal point y (center of image)\n\nK = np.array([[fx, 0, cx],\n              [0, fy, cy],\n              [0,  0,  1]])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert matched keypoints to normalized coordinates using K\npts1 = np.array([kp1[m.queryIdx].pt for m in good_matches])\npts2 = np.array([kp2[m.trainIdx].pt for m in good_matches])\n\n# Normalize points\npts1_norm = cv2.undistortPoints(np.expand_dims(pts1, axis=1), K, None)\npts2_norm = cv2.undistortPoints(np.expand_dims(pts2, axis=1), K, None)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"pts1 dtype:\", pts1.dtype, \" shape:\", pts1.shape)\nprint(\"pts1 contiguous?:\", pts1.flags['C_CONTIGUOUS'])\n\nprint(\"pts2 dtype:\", pts2.dtype, \" shape:\", pts2.shape)\nprint(\"pts2 contiguous?:\", pts2.flags['C_CONTIGUOUS'])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pts1 = np.ascontiguousarray(pts1, dtype=np.float32)\npts2 = np.ascontiguousarray(pts2, dtype=np.float32)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"pts1 shape:\", pts1.shape, \" dtype:\", pts1.dtype, \" contiguous?:\", pts1.flags['C_CONTIGUOUS'])\nprint(\"pts2 shape:\", pts2.shape, \" dtype:\", pts2.dtype, \" contiguous?:\", pts2.flags['C_CONTIGUOUS'])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Number of good matches:\", len(good_matches))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if len(good_matches) >= 8:\n    # Proceed as usual\n    ...\nelse:\n    print(\"Not enough matches to compute pose. Need at least 8, got\", len(good_matches))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sift = cv2.SIFT_create()\nkp1, des1 = sift.detectAndCompute(img1, None)\nkp2, des2 = sift.detectAndCompute(img2, None)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"bf = cv2.BFMatcher()\nmatches = bf.knnMatch(des1, des2, k=2)\n\n# Apply ratio test\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.75 * n.distance:\n        good_matches.append(m)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if m.distance < 0.9 * n.distance:\n    good_matches.append(m)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_matches = cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None)\nplt.imshow(img_matches)\nplt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport cv2\n\n# Assume you already have:\n# K      : Intrinsic matrix\n# R, t   : Output from cv2.recoverPose\n# pts1, pts2 : Matching keypoints (Nx2)\n\n# Step 1: Projection matrix for camera 1 (identity pose)\nP1 = K @ np.hstack((np.eye(3), np.zeros((3,1))))  # [I | 0]\n\n# Step 2: Projection matrix for camera 2 (recovered pose)\nP2 = K @ np.hstack((R, t))  # [R | t]\n\n# Step 3: Triangulate points\npts1 = pts1.T  # shape (2, N)\npts2 = pts2.T  # shape (2, N)\n\npts4d_hom = cv2.triangulatePoints(P1, P2, pts1, pts2)  # shape (4, N)\npts4d = pts4d_hom[:3] / pts4d_hom[3]  # Convert from homogeneous to 3D (shape 3xN)\n\n# (Optional) Transpose to get Nx3 array\npts3d = pts4d.T\n\nprint(\"Triangulated 3D points:\\n\", pts3d)\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d import Axes3D\n\n# Assuming pts3d is of shape (N, 3)\nfig = plt.figure()\nax = fig.add_subplot(111, projection='3d')\nax.scatter(pts3d[:, 0], pts3d[:, 1], pts3d[:, 2])\n\nax.set_xlabel('X')\nax.set_ylabel('Y')\nax.set_zlabel('Z')\nplt.show()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pts2d_1 = np.array([[523.4, 422.1]])  # from image 1\npts2d_2 = np.array([[518.7, 419.5]])  # from image 2\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nfrom scipy.optimize import least_squares\n\ndef project_points(X, R, t, K):\n    X = X.reshape(-1, 3)\n    X_cam = (R @ X.T + t).T\n    x_proj = X_cam[:, :2] / X_cam[:, 2:]\n    x_proj_h = (K[:2, :2] @ x_proj.T).T + K[:2, 2]\n    return x_proj_h\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def reprojection_error(params, pts3d, pts2d, K):\n    rvec = params[:3]\n    tvec = params[3:6]\n    R, _ = cv2.Rodrigues(rvec)\n    t = tvec.reshape(3, 1)\n    projected = project_points(pts3d, R, t, K)\n    return (projected - pts2d).ravel()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pts3d = pts4d[:3, :].T  # Convert from homogeneous to XYZ","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport cv2\nfrom scipy.optimize import least_squares\n\n# Step 1: Convert from homogeneous 4D to 3D\npts3d = pts4d[:3, :].T   # shape: (N, 3)\n\n# Step 2: Use the corresponding 2D points (say, pts1 for Camera 1)\npts2d = pts1.reshape(-1, 2)  # shape: (N, 2)\n\n# Step 3: Initial rotation vector from cv2.Rodrigues\nrvec_init, _ = cv2.Rodrigues(R)\nparams_init = np.hstack((rvec_init.ravel(), t.ravel()))\n\n# Step 4: Reprojection error function\ndef project_points(X, R, t, K):\n    X = X.reshape(-1, 3)\n    X_cam = (R @ X.T + t).T\n    x_proj = X_cam[:, :2] / X_cam[:, 2:]\n    x_proj_h = (K[:2, :2] @ x_proj.T).T + K[:2, 2]\n    return x_proj_h\n\ndef reprojection_error(params, pts3d, pts2d, K):\n    rvec = params[:3]\n    tvec = params[3:6]\n    R, _ = cv2.Rodrigues(rvec)\n    t = tvec.reshape(3, 1)\n    projected = project_points(pts3d, R, t, K)\n    return (projected - pts2d).ravel()\n\n# Step 5: Optimize\nres = least_squares(reprojection_error, params_init,\n                    args=(pts3d, pts2d, K))\n\n# Step 6: Get refined pose\nrvec_opt = res.x[:3]\ntvec_opt = res.x[3:6]\nR_opt, _ = cv2.Rodrigues(rvec_opt)\nt_opt = tvec_opt.reshape(3, 1)\n\nprint(\"Refined Rotation:\\n\", R_opt)\nprint(\"Refined Translation:\\n\", t_opt)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nbase_path = \"/kaggle/input/image-matching-challenge-2025\"\nfor root, dirs, files in os.walk(base_path):\n    print(\"Directory:\", root)\n    for name in files:\n        print(\"  File:\", name)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"scene_name = \"amy_gardens\"\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nscene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\n\n# Yeh check karega kya files hain wahan\nimage_list = sorted([f for f in os.listdir(image_dir) if f.lower().endswith(('.jpg', '.png', '.jpeg'))])\n\n# Show first 5 images\nprint(\"Images mil gayi hain:\", image_list[:5])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sift = cv2.SIFT_create()\n\n# Keypoints & Descriptors\nkp1, des1 = sift.detectAndCompute(img1, None)\nkp2, des2 = sift.detectAndCompute(img2, None)\n\n# Matching with FLANN\nindex_params = dict(algorithm=1, trees=5)\nsearch_params = dict(checks=50)\nflann = cv2.FlannBasedMatcher(index_params, search_params)\n\nmatches = flann.knnMatch(des1, des2, k=2)\n\n# Lowe's ratio test\ngood_matches = []\npts1 = []\npts2 = []\n\nfor m, n in matches:\n    if m.distance < 0.7 * n.distance:\n        good_matches.append(m)\n        pts1.append(kp1[m.queryIdx].pt)\n        pts2.append(kp2[m.trainIdx].pt)\n\npts1 = np.array(pts1, dtype=np.float32)\npts2 = np.array(pts2, dtype=np.float32)\n\nprint(\"Good matches:\", len(good_matches))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Essential Matrix shape:\", E.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"pts1:\", pts1.shape, \"pts2:\", pts2.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"mask_valid = np.isfinite(pts1).all(axis=1) & np.isfinite(pts2).all(axis=1)\npts1 = pts1[mask_valid]\npts2 = pts2[mask_valid]\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n\nif E is None or E.shape != (3, 3):\n    print(\"Invalid Essential Matrix. Skipping this image pair.\")\nelse:\n    _, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n\nif E is not None and E.shape == (3, 3):\n    _, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\nelse:\n    print(\"Essential matrix not valid:\", None if E is None else E.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if len(pts1) >= 8:\n    E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n\n    if E is not None and E.shape == (3, 3):\n        _, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\n    else:\n        print(\"Invalid Essential Matrix shape:\", None if E is None else E.shape)\nelse:\n    print(f\" Not enough matches to compute Essential Matrix. Got only {len(pts1)}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\n\n# Folder jahan images hain\nscene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\n\n# Image file names set karo\nimg1_name = \"peach_0000.png\"\nimg2_name = \"peach_0001.png\"\n\n# Load grayscale images\nimg1 = cv2.imread(f\"{image_dir}/{img1_name}\", cv2.IMREAD_GRAYSCALE)\nimg2 = cv2.imread(f\"{image_dir}/{img2_name}\", cv2.IMREAD_GRAYSCALE)\n\n# Check karo images sahi load hui ya nahi\nassert img1 is not None, \"Image 1 load nahi hui\"\nassert img2 is not None, \"Image 2 load nahi hui\"\n\n# SIFT detector\nsift = cv2.SIFT_create()\n\n# Detect and compute\nkp1, des1 = sift.detectAndCompute(img1, None)\nkp2, des2 = sift.detectAndCompute(img2, None)\n\n# FLANN matcher\nindex_params = dict(algorithm=1, trees=5)\nsearch_params = dict(checks=50)\nflann = cv2.FlannBasedMatcher(index_params, search_params)\n\nmatches = flann.knnMatch(des1, des2, k=2)\n\n# Ratio test\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.75 * n.distance:\n        good_matches.append(m)\n\nprint(\"Good matches found:\", len(good_matches))\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Matched keypoints nikaalo\npts1 = np.float32([kp1[m.queryIdx].pt for m in good_matches])\npts2 = np.float32([kp2[m.trainIdx].pt for m in good_matches])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Approximate intrinsic matrix (assuming image size ~1600x1200)\nK = np.array([\n    [1600, 0, 800],\n    [0, 1600, 600],\n    [0, 0, 1]\n], dtype=np.float64)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\nif E is None or E.shape != (3, 3):\n    print(\" Essential Matrix compute nahi hui\")\nelse:\n    print(\" Essential Matrix shape:\", E.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Pose recover karo\n_, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\nprint(\"Recovered Rotation:\\n\", R)\nprint(\"Recovered Translation:\\n\", t)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Projection matrices\nP1 = K @ np.hstack((np.eye(3), np.zeros((3, 1))))\nP2 = K @ np.hstack((R, t))\n\n# Triangulation\npts4d_hom = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)\npts3d = (pts4d_hom / pts4d_hom[3])[:3].T  # X, Y, Z points\nprint(\"Triangulated 3D points:\\n\", pts3d)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Required imports\nimport cv2\nimport numpy as np\nfrom matplotlib import pyplot as plt\nfrom tqdm import tqdm  # for progress bar\n\n# Intrinsic matrix (assuming approx calibration)\nK = np.array([[1600, 0, 800],\n              [0, 1600, 600],\n              [0, 0, 1]], dtype=np.float64)\n\n# Path setup\nscene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\nimage_list = sorted([f for f in os.listdir(image_dir) if f.endswith('.png')])\n\n# Use first image as reference\nref_img_name = image_list[0]\ncamera_poses = {ref_img_name: (np.eye(3), np.zeros((3, 1)))}  # R = I, t = 0\n\n# Store 3D points and their image observations\npoints_3d_all = []\nobservations_all = []\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ORB Detector\norb = cv2.ORB_create(5000)\nbf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)\n\n# Load reference image\nref_img = cv2.imread(f\"{image_dir}/{ref_img_name}\", cv2.IMREAD_GRAYSCALE)\nkp1, des1 = orb.detectAndCompute(ref_img, None)\n\nfor next_img_name in tqdm(image_list[1:], desc=\"Estimating poses\"):\n    next_img = cv2.imread(f\"{image_dir}/{next_img_name}\", cv2.IMREAD_GRAYSCALE)\n    kp2, des2 = orb.detectAndCompute(next_img, None)\n\n    # Match features\n    matches = bf.match(des1, des2)\n    matches = sorted(matches, key=lambda x: x.distance)\n\n    if len(matches) < 8:\n        print(f\" Not enough matches between {ref_img_name} and {next_img_name}\")\n        continue\n\n    pts1 = np.float32([kp1[m.queryIdx].pt for m in matches])\n    pts2 = np.float32([kp2[m.trainIdx].pt for m in matches])\n\n    # Estimate Essential matrix\n    E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n\n    if E is None or E.shape != (3, 3):\n        print(f\" Essential matrix computation failed for {next_img_name}\")\n        continue\n\n    # Recover pose\n    _, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\n\n    # Save pose for this image\n    camera_poses[next_img_name] = (R, t)\n\n    print(f\" Pose estimated for {next_img_name}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"triangulated_points = []\n\n# Reference pose\nR1, t1 = camera_poses[ref_img_name]\nP1 = K @ np.hstack((R1, t1))  # Projection matrix for reference image\n\nfor img_name in tqdm(list(camera_poses.keys())[1:], desc=\"Triangulating points\"):\n    R2, t2 = camera_poses[img_name]\n    P2 = K @ np.hstack((R2, t2))  # Projection matrix for the next image\n\n    # Load both images again\n    img1 = cv2.imread(f\"{image_dir}/{ref_img_name}\", cv2.IMREAD_GRAYSCALE)\n    img2 = cv2.imread(f\"{image_dir}/{img_name}\", cv2.IMREAD_GRAYSCALE)\n\n    # Detect and match features\n    kp1, des1 = orb.detectAndCompute(img1, None)\n    kp2, des2 = orb.detectAndCompute(img2, None)\n    matches = bf.match(des1, des2)\n    matches = sorted(matches, key=lambda x: x.distance)[:100]  # Top 100\n\n    if len(matches) < 8:\n        print(f\" Not enough matches for triangulation with {img_name}\")\n        continue\n\n    pts1 = np.float32([kp1[m.queryIdx].pt for m in matches])\n    pts2 = np.float32([kp2[m.trainIdx].pt for m in matches])\n\n    # Triangulate\n    pts1_hom = cv2.undistortPoints(pts1.reshape(-1,1,2), K, None)\n    pts2_hom = cv2.undistortPoints(pts2.reshape(-1,1,2), K, None)\n\n    pts_4d_hom = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)\n    pts_3d = (pts_4d_hom[:3] / pts_4d_hom[3]).T  # Convert to Nx3\n\n    triangulated_points.append(pts_3d)\n\n    print(f\" Triangulated {pts_3d.shape[0]} points from {ref_img_name} and {img_name}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport os\n\nscene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\nimage_list = sorted(os.listdir(image_dir))\n\nimg1_name = image_list[0]\nref_img_path = os.path.join(image_dir, img1_name)\n\nref_img = cv2.imread(ref_img_path, cv2.IMREAD_GRAYSCALE)\n\nif ref_img is None:\n    print(\" Image load nahi hui:\", ref_img_path)\nelse:\n    print(\" Image load hogayi:\", ref_img.shape)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\n\nscene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\nprint(\"Directory exists:\", os.path.exists(image_dir))\nprint(\"Files in directory:\", os.listdir(image_dir))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\n\nimage_dir = \"/kaggle/input/image-matching-challenge-2025/train/amy_gardens\"\nimage_list = sorted([f for f in os.listdir(image_dir) if f.endswith('.png')])\n\nimg1_name = image_list[0]\nref_img_path = os.path.join(image_dir, img1_name)\n\nref_img = cv2.imread(ref_img_path, cv2.IMREAD_GRAYSCALE)\n\nif ref_img is None:\n    print(\" Image load nahi hui:\", ref_img_path)\nelse:\n    print(\" Image load hogayi:\", ref_img.shape)\n\n    # Detect features\n    sift = cv2.SIFT_create()\n    kp1, des1 = sift.detectAndCompute(ref_img, None)\n    print(\"Keypoints found:\", len(kp1))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\ndef save_submission_file(points3D, camera_poses_dict, image_names, scene_name):\n    \"\"\"\n    points3D: Nx3 numpy array\n    camera_poses_dict: dict of {image_name: (R, t)} where R: 3x3, t: 3x1\n    image_names: list of image names in order\n    scene_name: e.g. \"amy_gardens\"\n    \"\"\"\n\n    # Projection matrices P = K [R|t]\n    K = np.array([\n        [2759.48, 0, 1520.69],\n        [0, 2764.16, 1006.81],\n        [0, 0, 1]\n    ])  # ← use correct intrinsics if needed\n\n    camera_poses = []\n    for name in image_names:\n        R, t = camera_poses_dict[name]\n        Rt = np.hstack([R, t])\n        P = K @ Rt\n        camera_poses.append(P)\n\n    camera_poses = np.stack(camera_poses)  # M x 3 x 4\n    points3D = np.array(points3D)          # N x 3\n\n    # Save as .npz\n    np.savez_compressed(f\"{scene_name}.npz\",\n                        points3D=points3D,\n                        camera_poses=camera_poses,\n                        image_names=np.array(image_names))\n\n    print(f\" Submission file saved: {scene_name}.npz\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"camera_poses_dict = camera_poses\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_names = sorted(os.listdir(image_dir))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_names = image_list","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"3D points collected:\", len(points_3d_all))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img1_name = \"peach_0000.png\"\nimg2_name = \"peach_0001.png\"\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if len(points_3d_all) > 0:\n    points3D = np.vstack(points_3d_all)\nelse:\n    print(\" Koi 3D point triangulate nahi hua.\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport os\n\n# Image paths\nscene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\nimg1_name = \"peach_0000.png\"\nimg2_name = \"peach_0001.png\"\nimg1_path = f\"{image_dir}/{img1_name}\"\nimg2_path = f\"{image_dir}/{img2_name}\"\n\n# Load images\nimg1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE)\nimg2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE)\n\n# Check images loaded\nprint(\"Image 1 shape:\", img1.shape)\nprint(\"Image 2 shape:\", img2.shape)\n\n# Camera intrinsics (example K)\nK = np.array([[1000, 0, img1.shape[1] // 2],\n              [0, 1000, img1.shape[0] // 2],\n              [0, 0, 1]])\n\n# SIFT + matching\nsift = cv2.SIFT_create()\nkp1, des1 = sift.detectAndCompute(img1, None)\nkp2, des2 = sift.detectAndCompute(img2, None)\n\nbf = cv2.BFMatcher()\nmatches = bf.knnMatch(des1, des2, k=2)\n\n# Lowe's ratio test\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.75 * n.distance:\n        good_matches.append(m)\n\nprint(\"Good matches found:\", len(good_matches))\n\n# Extract matched points\npts1 = np.float32([kp1[m.queryIdx].pt for m in good_matches])\npts2 = np.float32([kp2[m.trainIdx].pt for m in good_matches])\n\n# Compute essential matrix\nE, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, prob=0.999, threshold=1.0)\n\n# Recover pose\nif E is not None and E.shape == (3, 3):\n    _, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\n\n    # Projection matrices\n    P1 = np.hstack((np.eye(3), np.zeros((3, 1))))\n    P2 = np.hstack((R, t))\n\n    # Triangulate\n    pts1_tr = pts1[mask_pose.ravel() == 1]\n    pts2_tr = pts2[mask_pose.ravel() == 1]\n\n    if pts1_tr.shape[0] >= 8:\n        pts4d_hom = cv2.triangulatePoints(K @ P1, K @ P2, pts1_tr.T, pts2_tr.T)\n        pts3d = (pts4d_hom[:3] / pts4d_hom[3]).T\n        print(\" Triangulated 3D points:\", pts3d.shape)\n    else:\n        print(\" Not enough inliers to triangulate\")\nelse:\n    print(\" Essential matrix not valid\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"scene_name = \"amy_gardens\"\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\nimage_list = sorted(os.listdir(image_dir))\nprint(\"Images found:\", image_list)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\nK = np.array([\n    [1500, 0, 960],  # fx, 0, cx\n    [0, 1500, 540],  # 0, fy, cy\n    [0, 0, 1]\n])\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport os\n\nimage_dir = \"/kaggle/input/image-matching-challenge-2025/train/amy_gardens/peach_0000.png\"\nsift = cv2.SIFT_create()\n\nimg1 = cv2.imread(os.path.join(image_dir, \"peach_0000.png\"), cv2.IMREAD_GRAYSCALE)\nimg2 = cv2.imread(os.path.join(image_dir, \"peach_0001.png\"), cv2.IMREAD_GRAYSCALE)\n\n# Check if images are loaded\nif img1 is None or img2 is None:\n    print(\" Image not loaded. Check path.\")\nelse:\n    kp1, des1 = sift.detectAndCompute(img1, None)\n    kp2, des2 = sift.detectAndCompute(img2, None)\n\n    # FLANN matcher\n    FLANN_INDEX_KDTREE = 1\n    index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)\n    search_params = dict(checks=50)\n    flann = cv2.FlannBasedMatcher(index_params, search_params)\n    matches = flann.knnMatch(des1, des2, k=2)\n\n    good_matches = []\n    for m, n in matches:\n        if m.distance < 0.75 * n.distance:\n            good_matches.append(m)\n\n    print(f\"Good matches found: {len(good_matches)}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\n# Try finding peach_0000.png file\nfor root, dirs, files in os.walk(\"/kaggle/input/image-matching-challenge-2025\"):\n    for name in files:\n        if \"peach_0000\" in name:\n            print(\"Found:\", os.path.join(root, name))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\n\nscene_name = \"amy_gardens\"\nimage_name = \"peach_0000.png\"\n\nimage_dir = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\nimg_path = os.path.join(image_dir, image_name)\n\nimg = cv2.imread(img_path)\n\nif img is None:\n    print(\" Image not loaded, check path again:\", img_path)\nelse:\n    print(\" Image loaded successfully:\", img.shape)\n\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img1 = cv2.imread(os.path.join(image_dir, \"peach_0000.png\"))\nimg2 = cv2.imread(os.path.join(image_dir, \"peach_0001.png\"))\n\n# Convert to grayscale\ngray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)\ngray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)\n\n# Initialize SIFT\nsift = cv2.SIFT_create()\n\n# Detect keypoints and descriptors\nkp1, des1 = sift.detectAndCompute(gray1, None)\nkp2, des2 = sift.detectAndCompute(gray2, None)\n\n# Match features using FLANN\nFLANN_INDEX_KDTREE = 1\nindex_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)\nsearch_params = dict(checks=50)\nflann = cv2.FlannBasedMatcher(index_params, search_params)\nmatches = flann.knnMatch(des1, des2, k=2)\n\n# Lowe's ratio test\ngood_matches = []\nfor m, n in matches:\n    if m.distance < 0.75 * n.distance:\n        good_matches.append(m)\n\nprint(\"Good matches found:\", len(good_matches))\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport json\nfrom tqdm import tqdm\nfrom pathlib import Path\n\n# Scene ka naam sahi se likho (jo folder mein hai)\nscene_name = \"amy_gardens\"\nscene_path = f\"/kaggle/input/image-matching-challenge-2025/train/{scene_name}\"\noutput_path = \"/kaggle/working/submission.json\"\n\n# Images load karo\nimage_files = sorted([f for f in os.listdir(scene_path) if f.endswith(\".png\")])\nimage_paths = [os.path.join(scene_path, f) for f in image_files]\n\n# Dummy intrinsics (agar .npz available hai toh usse load karo)\nK = np.array([[1200, 0, 512], [0, 1200, 288], [0, 0, 1]])  # Focal length and principal point\n\n# SIFT detector\nsift = cv2.SIFT_create()\n\ndef extract_features(img_path):\n    img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n    if img is None:\n        print(f\"Failed to load: {img_path}\")\n        return None, None\n    kp, des = sift.detectAndCompute(img, None)\n    return kp, des\n\ndef match_features(desc1, desc2):\n    bf = cv2.BFMatcher()\n    matches = bf.knnMatch(desc1, desc2, k=2)\n    good = []\n    for m, n in matches:\n        if m.distance < 0.75 * n.distance:\n            good.append(m)\n    return good\n\ndef get_matched_points(kp1, kp2, matches):\n    pts1 = np.float32([kp1[m.queryIdx].pt for m in matches])\n    pts2 = np.float32([kp2[m.trainIdx].pt for m in matches])\n    return pts1, pts2\n\ndef estimate_pose(pts1, pts2, K):\n    E, mask = cv2.findEssentialMat(pts1, pts2, K, method=cv2.RANSAC, threshold=1.0)\n    _, R, t, mask_pose = cv2.recoverPose(E, pts1, pts2, K)\n    return R, t\n\ndef triangulate_points(R, t, pts1, pts2, K):\n    P1 = K @ np.hstack((np.eye(3), np.zeros((3, 1))))\n    P2 = K @ np.hstack((R, t))\n    pts1_h = cv2.convertPointsToHomogeneous(pts1)[:, 0, :]\n    pts2_h = cv2.convertPointsToHomogeneous(pts2)[:, 0, :]\n    points_4d = cv2.triangulatePoints(P1, P2, pts1.T, pts2.T)\n    points_3d = (points_4d[:3] / points_4d[3]).T\n    return points_3d\n\n#  Loop through image pairs\nresults = []\n\nfor i in tqdm(range(len(image_paths) - 1)):\n    img1_path = image_paths[i]\n    img2_path = image_paths[i + 1]\n    img1_name = Path(img1_path).name\n    img2_name = Path(img2_path).name\n\n    kp1, des1 = extract_features(img1_path)\n    kp2, des2 = extract_features(img2_path)\n\n    if des1 is None or des2 is None:\n        continue\n\n    matches = match_features(des1, des2)\n    if len(matches) < 10:\n        continue\n\n    pts1, pts2 = get_matched_points(kp1, kp2, matches)\n\n    try:\n        R, t = estimate_pose(pts1, pts2, K)\n        points_3d = triangulate_points(R, t, pts1, pts2, K)\n\n        pair_data = {\n            \"image0\": img1_name,\n            \"image1\": img2_name,\n            \"qvec\": [1.0, 0.0, 0.0, 0.0],  # identity quaternion (dummy)\n            \"tvec\": [float(t[0]), float(t[1]), float(t[2])],  # translation vector\n            \"points3D\": points_3d[:100].tolist()  # limit to first 100 points\n        }\n        results.append(pair_data)\n\n    except Exception as e:\n        print(f\"Failed on pair {img1_name}, {img2_name}: {e}\")\n        continue\n\n# Save submission file\nwith open(output_path, \"w\") as f:\n    json.dump(results, f)\n\nprint(f\"\\n Submission JSON saved to: {output_path}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Example: suppose you have list of image names and their camera poses\ndata = {\n    'image_name': ['peach_0000.png', 'peach_0001.png'],\n    'q_w': [1.0, 0.98],\n    'q_x': [0.0, 0.01],\n    'q_y': [0.0, -0.02],\n    'q_z': [0.0, 0.005],\n    't_x': [0.0, 1.2],\n    't_y': [0.0, -0.3],\n    't_z': [0.0, 0.5],\n}\n\ndf = pd.DataFrame(data)\ndf.to_csv(\"submission.csv\", index=False)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.to_csv(\"submission.csv\", index=False)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Example list of matches and their scores\ndata = {\n    \"pair_id\": [\n        \"peach_valley/peach_0000-0001.png\",\n        \"peach_valley/peach_0001-0002.png\"\n    ],\n    \"score\": [\n        0.8432,\n        0.9134\n    ]\n}\n\ndf = pd.DataFrame(data)\n\n# Save to submission.csv\ndf.to_csv(\"submission.csv\", index=False)\nprint(\" submission.csv file created successfully\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Dummy pose data (replace with actual estimates)\ndata = {\n    \"image_name\": [\"peach_0000.png\", \"peach_0001.png\"],\n    \"q_w\": [1.0, 0.99],\n    \"q_x\": [0.0, 0.01],\n    \"q_y\": [0.0, 0.02],\n    \"q_z\": [0.0, 0.03],\n    \"t_x\": [0.0, 0.1],\n    \"t_y\": [0.0, 0.2],\n    \"t_z\": [0.0, 0.3],\n}\n\ndf = pd.DataFrame(data)\n\n# Save to submission.csv\ndf.to_csv(\"submission.csv\", index=False)\nprint(\" submission.csv file created successfully\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}