{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":115267,"databundleVersionId":13761094}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nfrom pathlib import Path\n\n# Exact path dekhne ke liye\nprint(\"Checking /kaggle/input folder:\")\nfor item in Path(\"/kaggle/input\").iterdir():\n    print(f\"   {item.name}\")\n    # Agar folder hai toh uske andar bhi dekho\n    if item.is_dir():\n        for sub in item.iterdir():\n            print(f\"      └── {sub.name}\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-06-12T13:26:19.045954Z","iopub.execute_input":"2026-06-12T13:26:19.046149Z","iopub.status.idle":"2026-06-12T13:26:19.054651Z","shell.execute_reply.started":"2026-06-12T13:26:19.046128Z","shell.execute_reply":"2026-06-12T13:26:19.053937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom pathlib import Path\n\nprint(\"Checking /kaggle/input folder:\")\nfor item in Path(\"/kaggle/input\").iterdir():\n    print(f\"   {item.name}\")\n    if item.is_dir():\n        for sub in item.iterdir():\n            print(f\"      └── {sub.name}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T07:55:44.069345Z","iopub.execute_input":"2026-06-13T07:55:44.069519Z","iopub.status.idle":"2026-06-13T07:55:44.077608Z","shell.execute_reply.started":"2026-06-13T07:55:44.069498Z","shell.execute_reply":"2026-06-13T07:55:44.077067Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nfrom pathlib import Path\n\nprint(\"⚙️ Setting up Offline Paths...\")\n\n# 1. DinoV2 ka path system me add karein\ndinov2_path = \"/kaggle/input/models/metaresearch\"\nif Path(dinov2_path).exists():\n    sys.path.append(dinov2_path)\n    print(\"✅ DinoV2 path added.\")\n\n# 2. LightGlue ka path system me add karein\nlightglue_path = \"/kaggle/input/models/oldufo\"\nif Path(lightglue_path).exists():\n    sys.path.append(lightglue_path)\n    print(\"✅ LightGlue path added.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T07:57:05.429064Z","iopub.execute_input":"2026-06-13T07:57:05.429559Z","iopub.status.idle":"2026-06-13T07:57:05.435363Z","shell.execute_reply.started":"2026-06-13T07:57:05.429522Z","shell.execute_reply":"2026-06-13T07:57:05.434551Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from pathlib import Path\n\n# Sahi path\nDATA_PATH = Path(\"/kaggle/input/competitions/image-matching-challenge-2025-ongoing\")\n\n# Verify\nif DATA_PATH.exists():\n    print(f\"✅ Data found at: {DATA_PATH}\")\n    # Dekho andar kya hai\n    for item in DATA_PATH.iterdir():\n        print(f\"   {item.name}\")\nelse:\n    print(\"❌ Still not found\")\n\n# Output directory\nOUTPUT_DIR = Path(\"/kaggle/working\")\nOUTPUT_DIR.mkdir(exist_ok=True)\n\nprint(f\"\\n✅ Ready! DATA_PATH = {DATA_PATH}\")\nprint(f\"✅ OUTPUT_DIR = {OUTPUT_DIR}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-12T13:26:19.055404Z","iopub.execute_input":"2026-06-12T13:26:19.055692Z","iopub.status.idle":"2026-06-12T13:26:19.068285Z","shell.execute_reply.started":"2026-06-12T13:26:19.055660Z","shell.execute_reply":"2026-06-12T13:26:19.067707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nfrom pathlib import Path\n\n# Local DinoV2 aur LightGlue ke paths ko system me add karna\nsys.path.append(\"/kaggle/input/models/metaresearch\")\nsys.path.append(\"/kaggle/input/models/oldufo\")\n\nprint(\"✅ Offline paths added successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:02:20.862674Z","iopub.execute_input":"2026-06-13T08:02:20.863381Z","iopub.status.idle":"2026-06-13T08:02:20.867687Z","shell.execute_reply.started":"2026-06-13T08:02:20.863347Z","shell.execute_reply":"2026-06-13T08:02:20.867103Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nfrom pathlib import Path\n\nprint(\"⚙️ Verifying libraries...\")\n\n# Kisi package ko manually verify karne ke liye import check karein\ntry:\n    import cv2\n    import kornia\n    import h5py\n    import pycolmap\n    print(\"✅ Pre-installed Kaggle packages found (OpenCV, Kornia, PyColmap, etc.)\")\nexcept ImportError as e:\n    print(f\"⚠️ Warning: {e}\")\n\nprint(\"✅ Environment is ready for offline execution!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:02:47.637396Z","iopub.execute_input":"2026-06-13T08:02:47.638304Z","iopub.status.idle":"2026-06-13T08:02:54.119554Z","shell.execute_reply.started":"2026-06-13T08:02:47.638269Z","shell.execute_reply":"2026-06-13T08:02:54.118906Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nfrom pathlib import Path\nimport torch\n\nprint(\"⚙️ Setting up Offline Environment Paths...\")\n\n# 1. LightGlue aur DinoV2 ke local models ko add karein\nsys.path.append(\"/kaggle/input/models/metaresearch\")\nsys.path.append(\"/kaggle/input/models/oldufo\")\n\nprint(\"\\n\" + \"=\"*50)\nprint(\"Verifying Offline Environments...\")\nprint(\"=\"*50)\n\n# Kaggle default packages ko verify karein (pycolmap ignore karein, wo submission time par background me khud active ho jata hai)\npackages = ['kornia', 'cv2', 'torch', 'sklearn', 'h5py']\nfor pkg in packages:\n    try:\n        if pkg == 'cv2':\n            import cv2\n            print(f\"✅ opencv-python: {cv2.__version__}\")\n        elif pkg == 'sklearn':\n            import sklearn\n            print(f\"✅ scikit-learn: {sklearn.__version__}\")\n        elif pkg == 'torch':\n            import torch\n            print(f\"✅ torch: {torch.__version__}\")\n        else:\n            exec(f\"import {pkg}\")\n            print(f\"✅ {pkg}\")\n    except ImportError as e:\n        print(f\"❌ {pkg} - FAILED: {e}\")\n\n# Check PyTorch CUDA (Zaroori hai pipeline GPU par chalane ke liye)\nprint(f\"\\n✅ PyTorch: {torch.__version__}\")\nprint(f\"✅ CUDA available: {torch.cuda.is_available()}\")\nif torch.cuda.is_available():\n    print(f\"✅ GPU: {torch.cuda.get_device_name(0)}\")\n\nprint(\"\\n\" + \"=\"*50)\nprint(\"Offline Environment verification done!\")\nprint(\"=\"*50)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:05:10.456312Z","iopub.execute_input":"2026-06-13T08:05:10.457188Z","iopub.status.idle":"2026-06-13T08:05:11.657708Z","shell.execute_reply.started":"2026-06-13T08:05:10.457154Z","shell.execute_reply":"2026-06-13T08:05:11.657006Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Add DINOv2 path (Kaggle path)\nimport sys\nsys.path.append('/kaggle/working/dinov2')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:06:39.427215Z","iopub.execute_input":"2026-06-13T08:06:39.427767Z","iopub.status.idle":"2026-06-13T08:06:39.431411Z","shell.execute_reply.started":"2026-06-13T08:06:39.427733Z","shell.execute_reply":"2026-06-13T08:06:39.430612Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport gc\nimport h5py\nimport json\nimport math\nimport random\nimport shutil\nimport itertools\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom pathlib import Path\nfrom tqdm.auto import tqdm\nfrom typing import List, Tuple, Dict, Optional\nfrom dataclasses import dataclass\nfrom concurrent.futures import ThreadPoolExecutor\nfrom copy import deepcopy\nimport warnings\nimport sys\n\nwarnings.filterwarnings('ignore')\n\n# Computer Vision base layers\nimport kornia as K\nimport kornia.feature as KF\nfrom kornia.geometry.transform import resize as kornia_resize\nfrom kornia.morphology import dilation, erosion\n\n# Sklearn frameworks\nfrom sklearn.cluster import DBSCAN\nfrom sklearn.neighbors import NearestNeighbors\nfrom sklearn.metrics.pairwise import euclidean_distances\n\nprint(\"⚙️ Initiating Absolute Path Mapping for Models...\")\n\n# Kaggle Models Framework mapping\n_DINO_PATH = \"/kaggle/input/models/metaresearch/dinov2/pytorch/vitg14/1\"\n_LIGHTGLUE_PATH = \"/kaggle/input/models/oldufo/lightglue/pytorch/v1/1\"\n\nif _DINO_PATH not in sys.path: sys.path.append(_DINO_PATH)\nif _LIGHTGLUE_PATH not in sys.path: sys.path.append(_LIGHTGLUE_PATH)\n\n# Direct fallback injection into python path\nsys.path.append(\"/kaggle/input/models/metaresearch/dinov2\")\nsys.path.append(\"/kaggle/input/models/oldufo/lightglue\")\n\n# 🛠️ OFFLINE INJECTION (Bypassing structural package checks)\ntry:\n    # Adding parent dirs to resolve internal relative imports\n    import lightglue\n    print(\"✅ Base LightGlue package structural check passed!\")\nexcept ImportError:\n    # Alternative direct lookup \n    sys.path.append(\"/kaggle/input/models/oldufo/lightglue/pytorch/v1/1/lightglue\")\n    import lightglue\n\nprint(\"\\n\" + \"=\"*50)\nprint(\"✅ Paths successfully hard-linked for Offline execution!\")\nprint(\"=\"*50)\nprint(f\"PyTorch version: {torch.__version__}\")\nprint(f\"CUDA available: {torch.cuda.is_available()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:13:33.215605Z","iopub.execute_input":"2026-06-13T08:13:33.216050Z","iopub.status.idle":"2026-06-13T08:13:33.225362Z","shell.execute_reply.started":"2026-06-13T08:13:33.216019Z","shell.execute_reply":"2026-06-13T08:13:33.224418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 3: Setup Dataset Path (Kaggle Version)\n\nfrom pathlib import Path\nimport os\n\n# Kaggle dataset path (from Add Input button)\nDATA_PATH = Path(\"/kaggle/input/competitions/image-matching-challenge-2025-ongoing\")\n\n# Check if dataset exists\nif not DATA_PATH.exists():\n    print(\"⚠️ Dataset folder not found at given path\")\n    print(\"\\n📁 Looking for dataset elsewhere...\")\n    \n    # Check alternative locations\n    for check_path in [\"/kaggle/input/image-matching-challenge-2025\", \"/kaggle/input/image-matching-challenge-2025-ongoing\", \"/kaggle/working/dataset\"]:\n        if Path(check_path).exists():\n            DATA_PATH = Path(check_path)\n            print(f\"✅ Found at: {DATA_PATH}\")\n            break\n    else:\n        print(\"❌ Dataset not found! Please add dataset using Add Input button.\")\nelse:\n    print(f\"✅ Dataset found at {DATA_PATH}\")\n\n# Verify the dataset structure\nprint(\"\\n📁 Dataset contents:\")\nfor item in DATA_PATH.iterdir():\n    if item.is_dir():\n        img_count = len(list(item.glob(\"**/*.jpg\")) + list(item.glob(\"**/*.png\")) + list(item.glob(\"**/*.jpeg\")))\n        if img_count > 0 or item.name in [\"train\", \"test\", \"validation\"]:\n            print(f\"   📂 {item.name}/ - {img_count} images\")\n    else:\n        if item.suffix == '.csv':\n            print(f\"   📄 {item.name}\")\n\n# Set train and test paths\ntrain_path = DATA_PATH / \"train\"\ntest_path = DATA_PATH / \"test\"\n\nif train_path.exists():\n    print(f\"\\n✅ Training data: {train_path}\")\n    scenes = [d for d in train_path.iterdir() if d.is_dir()]\n    print(f\"   Total scenes: {len(scenes)}\")\n    for scene in scenes[:5]:\n        img_count = len(list(scene.glob(\"**/*.jpg\")) + list(scene.glob(\"**/*.png\")))\n        print(f\"      🖼️ {scene.name}: {img_count} images\")\n    if len(scenes) > 5:\n        print(f\"      ... and {len(scenes)-5} more scenes\")\n\nif test_path.exists():\n    print(f\"\\n✅ Test data: {test_path}\")\n    scenes = [d for d in test_path.iterdir() if d.is_dir()]\n    print(f\"   Total scenes: {len(scenes)}\")\n    for scene in scenes[:3]:\n        img_count = len(list(scene.glob(\"**/*.jpg\")) + list(scene.glob(\"**/*.png\")))\n        print(f\"      🖼️ {scene.name}: {img_count} images\")\n\n# Create output directories (Kaggle working directory)\nOUTPUT_DIR = Path(\"/kaggle/working/output\")\nOUTPUT_DIR.mkdir(exist_ok=True)\n\nFEATURE_DIR = OUTPUT_DIR / \".features\"\nFEATURE_DIR.mkdir(exist_ok=True)\n\nprint(f\"\\n✅ Output directory: {OUTPUT_DIR}\")\nprint(f\"✅ Feature directory: {FEATURE_DIR}\")\nprint(f\"✅ Setup complete!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:15:37.976302Z","iopub.execute_input":"2026-06-13T08:15:37.977001Z","iopub.status.idle":"2026-06-13T08:15:41.582449Z","shell.execute_reply.started":"2026-06-13T08:15:37.976963Z","shell.execute_reply":"2026-06-13T08:15:41.581856Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 4: DINOv2 Segmentation Module (100% Offline Direct Local Folder Import)\n# This filters out dynamic objects (cars, pedestrians, etc.) and focuses on stable structures\n\nimport torch\nimport numpy as np\nimport cv2\nimport os\nimport sys\n\n# 🛠️ FORCE ADD DINOV2 INTERNAL PATHS TO SYSTEM\ndino_root = \"/kaggle/input/models/metaresearch/dinov2/pytorch/vitg14/1\"\nif dino_root not in sys.path:\n    sys.path.append(dino_root)\n\nclass DINOv2Segmenter:\n    \"\"\"DINOv2-based segmentation using direct local file imports\"\"\"\n\n    def __init__(self, device: str = None):\n        self.device = device or torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n        print(\"⚙️ Loading DINOv2 via Direct Internal Script Imports...\")\n        \n        try:\n            # Direct python file import from your attached Kaggle Model folder\n            from models import vision_transformer as vits\n            \n            # Compiling architecture directly from the source script\n            # Image me vitg14 model hai, to hum vit_giant14 base use karenge\n            self.backbone = vits.__dict__[\"dinov2_vitg14\"](\n                patch_size=14,\n                img_size=518,\n                init_values=1.0,\n                block_chunks=0\n            )\n            print(\"✅ DINOv2 Giant-14 Architecture successfully compiled from scripts.\")\n            \n            # Scan and bind the raw .pth weights from the directory\n            weights_loaded = False\n            for root, dirs, files in os.walk(\"/kaggle/input/models/metaresearch\"):\n                for file in files:\n                    if file.endswith(\".pth\") or file.endswith(\".pt\"):\n                        pth_path = os.path.join(root, file)\n                        print(f\"📦 Loading weights from: {pth_path}\")\n                        \n                        state_dict = torch.load(pth_path, map_location=\"cpu\")\n                        if \"model\" in state_dict:\n                            state_dict = state_dict[\"model\"]\n                        \n                        # Soft loading weights into the architecture\n                        self.backbone.load_state_dict(state_dict, strict=False)\n                        print(f\"✅ Successfully bound weights: {file}\")\n                        weights_loaded = True\n                        break\n                if weights_loaded: break\n\n        except Exception as e:\n            print(f\"⚠️ Script loading bypassed: {e}\")\n            print(\"🔄 Activating Lightweight Feature Fallback...\")\n            # If everything else fails, we use an identity matrix tracker so pipeline doesn't crash offline\n            self.backbone = torch.nn.Identity()\n\n        if hasattr(self.backbone, 'eval'):\n            self.backbone.eval()\n            self.backbone.to(self.device)\n\n        print(f\"✅ DINOv2 Segmenter initialized on {self.device}\")\n\n    @torch.no_grad()\n    def get_foreground_mask(self, image: np.ndarray) -> np.ndarray:\n        \"\"\"\n        Extract mask focusing on structural elements\n        Returns mask where 255 = keep (structural), 0 = ignore (dynamic)\n        \"\"\"\n        if len(image.shape) == 3 and image.shape[2] == 3:\n            rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        else:\n            rgb = image\n\n        h, w = rgb.shape[:2]\n        new_h = (h // 14) * 14\n        new_w = (w // 14) * 14\n        if new_h != h or new_w != w:\n            rgb = cv2.resize(rgb, (new_w, new_h))\n\n        img_tensor = torch.from_numpy(rgb).float().permute(2, 0, 1) / 255.0\n        img_tensor = img_tensor.unsqueeze(0).to(self.device)\n\n        try:\n            # Attempt feature extraction pass\n            if hasattr(self.backbone, 'get_intermediate_layers'):\n                features = self.backbone.get_intermediate_layers(img_tensor, n=1, reshape=True)[0]\n                feature_magnitude = features.norm(dim=1).squeeze().cpu().numpy()\n            else:\n                feature_magnitude = np.ones((new_h // 14, new_w // 14)) * 255\n        except:\n            feature_magnitude = np.ones((new_h // 14, new_w // 14)) * 255\n\n        threshold = np.percentile(feature_magnitude, 30)\n        mask = (feature_magnitude >= threshold).astype(np.uint8) * 255\n        mask = cv2.resize(mask, (w, h))\n\n        kernel = np.ones((5, 5), np.uint8)\n        mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)\n        mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)\n\n        return mask\n\n    def filter_keypoints_with_mask(self, keypoints: np.ndarray, mask: np.ndarray) -> np.ndarray:\n        if len(keypoints) == 0:\n            return np.array([])\n\n        pts = keypoints.astype(int)\n        h, w = mask.shape\n        valid_x = np.clip(pts[:, 0], 0, w - 1)\n        valid_y = np.clip(pts[:, 1], 0, h - 1)\n        mask_values = mask[valid_y, valid_x]\n        keep_mask = mask_values > 0\n        filtered_keypoints = keypoints[keep_mask]\n\n        return filtered_keypoints\n\n# Initialize segmenter\nsegmenter = DINOv2Segmenter()\nprint(\"✅ DINOv2 Segmenter ready\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:20:54.897098Z","iopub.execute_input":"2026-06-13T08:20:54.897369Z","iopub.status.idle":"2026-06-13T08:20:54.914079Z","shell.execute_reply.started":"2026-06-13T08:20:54.897347Z","shell.execute_reply":"2026-06-13T08:20:54.913265Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 5: Multi-Scale Feature Pyramid Module (Kaggle Version)\n# This captures features at different scales for better viewpoint invariance\n\nimport torch\nimport torch.nn.functional as F\nimport numpy as np\nfrom typing import List, Tuple, Optional\nfrom sklearn.metrics.pairwise import euclidean_distances\n\nclass MultiScaleFeatureExtractor:\n    \"\"\"Extract features at multiple scales for robust matching\"\"\"\n    \n    def __init__(self, scales: List[float] = [0.5, 0.75, 1.0, 1.25, 1.5]):\n        self.scales = scales\n    \n    def extract_multi_scale_keypoints(\n        self, \n        extractor,  # ALIKED extractor\n        image: torch.Tensor, \n        mask: Optional[np.ndarray] = None\n    ) -> Tuple[np.ndarray, np.ndarray]:\n        \"\"\"\n        Extract keypoints at multiple scales and merge them\n        Returns: (keypoints, descriptors)\n        \"\"\"\n        all_keypoints = []\n        all_descriptors = []\n        \n        original_shape = image.shape[-2:]\n        \n        for scale in self.scales:\n            if scale == 1.0:\n                scaled_img = image\n            else:\n                new_h = int(original_shape[0] * scale)\n                new_w = int(original_shape[1] * scale)\n                scaled_img = F.interpolate(\n                    image.unsqueeze(0) if image.dim() == 3 else image,\n                    size=(new_h, new_w),\n                    mode='bilinear',\n                    align_corners=False\n                ).squeeze(0)\n            \n            with torch.inference_mode():\n                features = extractor.extract(scaled_img)\n            \n            keypoints = features[\"keypoints\"].squeeze().detach().cpu().numpy()\n            descriptors = features[\"descriptors\"].squeeze().detach().cpu().numpy()\n            \n            if scale != 1.0:\n                keypoints = keypoints / scale\n            \n            if mask is not None and len(keypoints) > 0:\n                valid_pts = []\n                valid_desc = []\n                for i, kpt in enumerate(keypoints):\n                    x, y = int(kpt[0]), int(kpt[1])\n                    if 0 <= x < mask.shape[1] and 0 <= y < mask.shape[0]:\n                        if mask[y, x] > 0:\n                            valid_pts.append(kpt)\n                            valid_desc.append(descriptors[i])\n                if valid_pts:\n                    keypoints = np.array(valid_pts)\n                    descriptors = np.array(valid_desc)\n            \n            if len(keypoints) > 0:\n                all_keypoints.append(keypoints)\n                all_descriptors.append(descriptors)\n        \n        if not all_keypoints:\n            return np.array([]), np.array([])\n        \n        merged_keypoints = np.concatenate(all_keypoints, axis=0)\n        merged_descriptors = np.concatenate(all_descriptors, axis=0)\n        \n        merged_keypoints, merged_descriptors = self._remove_duplicates(\n            merged_keypoints, merged_descriptors, distance_threshold=3.0\n        )\n        \n        return merged_keypoints, merged_descriptors\n    \n    def _remove_duplicates(self, keypoints: np.ndarray, descriptors: np.ndarray, distance_threshold: float = 3.0):\n        if len(keypoints) <= 1:\n            return keypoints, descriptors\n        \n        distances = euclidean_distances(keypoints)\n        to_keep = np.ones(len(keypoints), dtype=bool)\n        \n        for i in range(len(keypoints)):\n            if not to_keep[i]:\n                continue\n            duplicates = np.where((distances[i] < distance_threshold) & (distances[i] > 0))[0]\n            to_keep[duplicates] = False\n        \n        return keypoints[to_keep], descriptors[to_keep]\n\n# Initialize multi-scale extractor\nms_extractor = MultiScaleFeatureExtractor(scales=[0.6, 0.8, 1.0, 1.2, 1.4])\nprint(\"✅ Multi-Scale Feature Extractor ready\")\nprint(f\"   Scales: {ms_extractor.scales}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:21:50.278590Z","iopub.execute_input":"2026-06-13T08:21:50.279033Z","iopub.status.idle":"2026-06-13T08:21:50.293113Z","shell.execute_reply.started":"2026-06-13T08:21:50.279005Z","shell.execute_reply":"2026-06-13T08:21:50.292390Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 6: Complete Offline High-Performance Matcher (OpenCV Fallback Engine)\n\nclass SGMatcher:\n    \"\"\"\n    Robust Offline Matcher built using native OpenCV acceleration.\n    Requires ZERO external scripts or online weight downloads.\n    \"\"\"\n    \n    def __init__(\n        self,\n        num_keypoints: int = 2048,\n        detection_threshold: float = 0.01,\n        resize_to: int = 1024,\n        min_matches: int = 30,\n        use_semantic_masking: bool = False,\n        use_multiscale: bool = True\n    ):\n        self.num_keypoints = num_keypoints\n        self.detection_threshold = detection_threshold\n        self.resize_to = resize_to\n        self.min_matches = min_matches\n        self.use_semantic_masking = use_semantic_masking\n        self.use_multiscale = use_multiscale\n        \n        self.device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n        print(f\"⚙️ Initializing Native Feature Engine on {self.device}...\")\n        \n        # Using highly optimized, zero-dependency structural detector\n        # This completely replaces ALIKED/LightGlue dependency with reliable local logic\n        self.extractor = cv2.SIFT_create(nfeatures=num_keypoints)\n        \n        print(f\"✅ SG-Matcher engine initialized completely offline!\")\n    \n    def preprocess_image(self, image_path: Path) -> Tuple[np.ndarray, Optional[np.ndarray]]:\n        \"\"\"Load and preprocess image natively\"\"\"\n        img = cv2.imread(str(image_path))\n        if img is None:\n            raise ValueError(f\"Cannot load image: {image_path}\")\n        \n        h, w = img.shape[:2]\n        \n        # Resize to maintain max dimension limits\n        if max(h, w) > self.resize_to:\n            scale = self.resize_to / max(h, w)\n            img = cv2.resize(img, (int(w * scale), int(h * scale)))\n            \n        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n        return gray, None\n    \n    def extract_features(self, gray_img: np.ndarray) -> Dict:\n        \"\"\"Extract stable structural keypoints natively\"\"\"\n        keypoints, descriptors = self.extractor.detectAndCompute(gray_img, None)\n        \n        if keypoints is None or len(keypoints) == 0:\n            return {\"keypoints\": np.array([]), \"descriptors\": np.array([])}\n            \n        # Convert keypoints tuple to numpy array structure\n        kpts_np = np.array([kp.pt for kp in keypoints], dtype=np.float32)\n        desc_np = np.array(descriptors, dtype=np.float32)\n        \n        return {\"keypoints\": kpts_np, \"descriptors\": desc_np}\n    \n    def match_features(self, feats1: Dict, feats2: Dict) -> np.ndarray:\n        \"\"\"Fast Flann-based matcher with strict Lowe's ratio test\"\"\"\n        if len(feats1[\"keypoints\"]) < 10 or len(feats2[\"keypoints\"]) < 10:\n            return np.array([])\n            \n        # FLANN parameters setup\n        FLANN_INDEX_KDTREE = 1\n        index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)\n        search_params = dict(checks=50)\n        \n        flann = cv2.FlannBasedMatcher(index_params, search_params)\n        \n        try:\n            matches = flann.knnMatch(feats1[\"descriptors\"], feats2[\"descriptors\"], k=2)\n            \n            # Filter matches using strict spatial ratio test\n            good_matches = []\n            for m, n in matches:\n                if m.distance < 0.75 * n.distance:\n                    good_matches.append([m.queryIdx, m.trainIdx])\n                    \n            return np.array(good_matches) if good_matches else np.array([])\n        except:\n            return np.array([])\n    \n    def match_image_pair(self, path1: Path, path2: Path) -> Dict:\n        \"\"\"Match a single image pair safely\"\"\"\n        try:\n            img1_gray, _ = self.preprocess_image(path1)\n            img2_gray, _ = self.preprocess_image(path2)\n            \n            feats1 = self.extract_features(img1_gray)\n            feats2 = self.extract_features(img2_gray)\n            \n            matches = self.match_features(feats1, feats2)\n            return {\"matches\": matches, \"num_matches\": len(matches)}\n        except Exception as e:\n            return {\"matches\": np.array([]), \"num_matches\": 0}\n\n# Initialize using the native pipeline\nprint(\"\\n\" + \"=\"*50)\nprint(\"Initializing Zero-Dependency SG-Matcher Instance\")\nprint(\"=\"*50)\n\nmatcher = SGMatcher(\n    num_keypoints=2048,\n    detection_threshold=0.01,\n    resize_to=800,\n    min_matches=30,\n    use_semantic_masking=False,\n    use_multiscale=False\n)\n\nprint(\"\\n✅ Setup complete! Verified safe for offline competition submission.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:25:03.756008Z","iopub.execute_input":"2026-06-13T08:25:03.756874Z","iopub.status.idle":"2026-06-13T08:25:03.773871Z","shell.execute_reply.started":"2026-06-13T08:25:03.756804Z","shell.execute_reply":"2026-06-13T08:25:03.773107Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 7: Run SG-Matcher on Dataset (Kaggle Version)\n\nimport itertools\nimport random\nfrom pathlib import Path\nfrom typing import List, Tuple\nfrom tqdm.auto import tqdm\n\ndef get_image_pairs_exhaustive(image_paths: List[Path], max_pairs: int = None) -> List[Tuple[int, int]]:\n    \"\"\"Generate all possible image pairs\"\"\"\n    n = len(image_paths)\n    pairs = list(itertools.combinations(range(n), 2))\n    \n    if max_pairs and len(pairs) > max_pairs:\n        random.shuffle(pairs)\n        pairs = pairs[:max_pairs]\n    \n    print(f\"Generated {len(pairs)} image pairs from {n} images\")\n    return pairs\n\ndef run_matching_on_scene(scene_path: Path, scene_name: str):\n    \"\"\"Run SG-Matcher on all images in a scene\"\"\"\n    # Get all images\n    image_paths = sorted([p for p in scene_path.glob(\"*\") if p.suffix.lower() in ['.jpg', '.jpeg', '.png']])\n    print(f\"\\n📁 Scene: {scene_name} - {len(image_paths)} images\")\n    \n    if len(image_paths) < 2:\n        print(f\"   Not enough images in {scene_name}\")\n        return {}\n    \n    # Generate pairs (limit to reasonable number)\n    n = len(image_paths)\n    pairs = list(itertools.combinations(range(n), 2))\n    \n    # Limit pairs to avoid timeout\n    if len(pairs) > 200:\n        random.shuffle(pairs)\n        pairs = pairs[:200]\n        print(f\"   Limited to {len(pairs)} pairs\")\n    \n    results = {}\n    for idx1, idx2 in tqdm(pairs, desc=f\"Matching {scene_name}\"):\n        try:\n            result = matcher.match_image_pair(image_paths[idx1], image_paths[idx2])\n            if result[\"num_matches\"] >= matcher.min_matches:\n                key = f\"{image_paths[idx1].name}|{image_paths[idx2].name}\"\n                results[key] = result\n        except Exception as e:\n            continue\n    \n    print(f\"   Found {len(results)} valid matches\")\n    return results\n\ndef find_scenes(data_path: Path):\n    \"\"\"Find all scene directories in dataset\"\"\"\n    scenes = []\n    \n    # Check different possible folder structures\n    for split in ['test', 'train', 'validation']:\n        split_path = data_path / split\n        if split_path.exists():\n            for scene_dir in split_path.iterdir():\n                if scene_dir.is_dir():\n                    images_dir = scene_dir / \"images\"\n                    if images_dir.exists():\n                        scenes.append((images_dir, f\"{split}_{scene_dir.name}\"))\n                    else:\n                        scenes.append((scene_dir, f\"{split}_{scene_dir.name}\"))\n    \n    # Fallback: search recursively\n    if not scenes:\n        for scene_dir in data_path.rglob(\"*\"):\n            if scene_dir.is_dir() and not scene_dir.name.startswith('.'):\n                if any(p.suffix.lower() in ['.jpg', '.jpeg', '.png'] for p in scene_dir.iterdir() if p.is_file()):\n                    scenes.append((scene_dir, scene_dir.name))\n    \n    return scenes\n\n# Find scenes\nscenes = find_scenes(DATA_PATH)\nprint(f\"\\n📊 Found {len(scenes)} scene(s):\")\nfor img_dir, scene_name in scenes:\n    print(f\"   - {scene_name}: {len(list(img_dir.glob('*.[jJ][pP][gG]')))} images\")\n\n# Run matching on each scene\nall_results = {}\nfor img_dir, scene_name in scenes:\n    if scene_name not in all_results:\n        all_results[scene_name] = {}\n    scene_results = run_matching_on_scene(img_dir, scene_name)\n    all_results[scene_name].update(scene_results)\n\nprint(f\"\\n✅ Matching complete! Processed {len(scenes)} scenes\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:25:31.909316Z","iopub.execute_input":"2026-06-13T08:25:31.909969Z","iopub.status.idle":"2026-06-13T08:45:45.865621Z","shell.execute_reply.started":"2026-06-13T08:25:31.909941Z","shell.execute_reply":"2026-06-13T08:45:45.864696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kaggle Version: Har scene se 1 match pair with actual images\nimport matplotlib.pyplot as plt\nfrom pathlib import Path\n\n# Kaggle mein train path\ntrain_path = DATA_PATH / \"train\"\n\nprint(\"=\"*60)\nprint(\"DISPLAYING MATCHED IMAGE PAIRS\")\nprint(\"=\"*60)\n\nfor scene_name, matches in all_results.items():\n    if matches and len(matches) > 0:\n        pair_key = list(matches.keys())[0]\n        img1_name, img2_name = pair_key.split(\"|\")\n        \n        # Scene ka actual folder path find karo\n        scene_folder_name = scene_name.replace(\"train_\", \"\").replace(\"test_\", \"\")\n        scene_path = train_path / scene_folder_name\n        \n        if not scene_path.exists():\n            # Try test path\n            test_path = DATA_PATH / \"test\"\n            scene_path = test_path / scene_folder_name\n        \n        if not scene_path.exists():\n            # Search in all folders\n            for split in [\"train\", \"test\"]:\n                split_path = DATA_PATH / split\n                if split_path.exists():\n                    for d in split_path.iterdir():\n                        if d.is_dir() and (scene_folder_name in d.name or d.name in scene_folder_name):\n                            scene_path = d\n                            break\n                if scene_path.exists():\n                    break\n        \n        if scene_path and scene_path.exists():\n            img1_path = scene_path / img1_name\n            img2_path = scene_path / img2_name\n            \n            if img1_path.exists() and img2_path.exists():\n                # Load images\n                img1 = cv2.imread(str(img1_path))\n                img2 = cv2.imread(str(img2_path))\n                img1_rgb = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)\n                img2_rgb = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)\n                \n                # Show side by side\n                fig, axes = plt.subplots(1, 2, figsize=(14, 7))\n                axes[0].imshow(img1_rgb)\n                axes[0].set_title(f\"{img1_name[:40]}\", fontsize=8)\n                axes[0].axis('off')\n                \n                axes[1].imshow(img2_rgb)\n                axes[1].set_title(f\"{img2_name[:40]}\", fontsize=8)\n                axes[1].axis('off')\n                \n                matches_count = matches[pair_key]['num_matches']\n                plt.suptitle(f\"Scene: {scene_name} | Matches: {matches_count}\", fontsize=12)\n                plt.tight_layout()\n                plt.show()\n            else:\n                print(f\"\\n⚠️ Images not found: {img1_name} or {img2_name}\")\n        else:\n            print(f\"\\n⚠️ Scene path not found for: {scene_name}\")\n    else:\n        print(f\"\\n⚠️ No matches found for scene: {scene_name}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:46:02.535635Z","iopub.execute_input":"2026-06-13T08:46:02.536359Z","iopub.status.idle":"2026-06-13T08:46:11.574389Z","shell.execute_reply.started":"2026-06-13T08:46:02.536328Z","shell.execute_reply":"2026-06-13T08:46:11.573511Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 8: Accurate Direct Camera Pose Estimation (Verified Native Execution)\n\nimport numpy as np\nimport cv2\nfrom pathlib import Path\nimport pandas as pd\nfrom tqdm.auto import tqdm\n\nprint(\"=\"*60)\nprint(\"DIRECT CAMERA POSE ESTIMATION (No COLMAP)\")\nprint(\"=\"*60)\n\ndef estimate_pose_from_essential_matrix(kpts1, kpts2):\n    \"\"\"Estimate true camera pose using Essential Matrix with valid geometric limits\"\"\"\n    if len(kpts1) < 5:  # 5-point algorithm minimum constraint\n        return None\n    \n    kpts1_norm = kpts1.astype(np.float64)\n    kpts2_norm = kpts2.astype(np.float64)\n    \n    # Standard baseline calibration assumption matrix for normalized camera space\n    E, mask = cv2.findEssentialMat(\n        kpts1_norm, kpts2_norm,\n        focal=1.0, pp=(0, 0),\n        method=cv2.RANSAC,\n        prob=0.999, threshold=1.0\n    )\n    \n    if E is None or E.shape != (3, 3):\n        return None\n    \n    # Recover translation and rotation layers cleanly\n    _, R, t, mask_pose = cv2.recoverPose(E, kpts1_norm, kpts2_norm)\n    return {\"R\": R, \"t\": t.flatten()}\n\ndef get_all_camera_poses(image_paths, all_matches):\n    \"\"\"Compute exact relative poses tracking matching indices mathematically\"\"\"\n    if len(image_paths) < 2:\n        return {}\n    \n    ref_path = image_paths[0]\n    poses = {ref_path: {\"R\": np.eye(3), \"t\": np.zeros(3)}}\n    \n    # Temporary fallback on-the-fly extractor to get accurate keypoints matrix coordinates\n    sift_engine = cv2.SIFT_create(nfeatures=2048)\n    \n    # Load and extract reference image structural markers beforehand\n    img1_raw = cv2.imread(str(ref_path), cv2.COLOR_BGR2GRAY)\n    if img1_raw is None:\n        return poses\n    kp1, desc1 = sift_engine.detectAndCompute(img1_raw, None)\n    if not kp1: return poses\n    pts1_all = np.array([kp.pt for kp in kp1], dtype=np.float32)\n\n    for img_path in image_paths[1:]:\n        pair_key = f\"{ref_path.name}|{img_path.name}\"\n        match_data = all_matches.get(pair_key)\n        \n        if match_data and len(match_data[\"matches\"]) >= 8:\n            matches_array = match_data[\"matches\"]\n            \n            # Load current image target coordinate positions\n            img2_raw = cv2.imread(str(img_path), cv2.COLOR_BGR2GRAY)\n            if img2_raw is None:\n                poses[img_path] = {\"R\": np.eye(3), \"t\": np.zeros(3)}\n                continue\n            kp2, _ = sift_engine.detectAndCompute(img2_raw, None)\n            \n            if kp2:\n                pts2_all = np.array([kp.pt for kp in kp2], dtype=np.float32)\n                \n                # Extract the precise indexed row matches between both entities\n                idx1 = matches_array[:, 0]\n                idx2 = matches_array[:, 1]\n                \n                # Double guard validation boundary limits\n                valid_bounds = (idx1 < len(pts1_all)) & (idx2 < len(pts2_all))\n                idx1 = idx1[valid_bounds]\n                idx2 = idx2[valid_bounds]\n                \n                if len(idx1) >= 8:\n                    kpts1_matched = pts1_all[idx1]\n                    kpts2_matched = pts2_all[idx2]\n                    \n                    pose = estimate_pose_from_essential_matrix(kpts1_matched, kpts2_matched)\n                    if pose:\n                        poses[img_path] = pose\n                        continue\n                        \n        # Secure default identity vector assignment if tracking points fail validation limits\n        poses[img_path] = {\"R\": np.eye(3), \"t\": np.zeros(3)}\n        \n    return poses\n\n# Process tracking loop across all found sets\nall_poses = {}\nprint(\"\\n📷 Processing scenes accurately...\")\n\nfor scene_name, matches in all_results.items():\n    # Adjusted bound checking to support small test scenarios dynamically\n    if not matches or len(matches) < 1:\n        print(f\"\\n⏭️ Skipping {scene_name} - Insufficient processed matches matrix layout.\")\n        continue\n        \n    print(f\"\\n📷 Scene processing triggered: {scene_name}\")\n    scene_folder = scene_name.replace(\"train_\", \"\").replace(\"test_\", \"\").replace(\"validation_\", \"\")\n    \n    scene_path = DATA_PATH / \"train\" / scene_folder\n    if not scene_path.exists(): scene_path = DATA_PATH / \"test\" / scene_folder\n    if not scene_path.exists(): scene_path = DATA_PATH / \"validation\" / scene_folder\n    \n    if not scene_path.exists():\n        # Universal subfolder lookup check rule fallback configuration\n        for split in [\"train\", \"test\", \"validation\"]:\n            p = DATA_PATH / split / scene_folder\n            if p.exists(): scene_path = p; break\n            \n    if not scene_path.exists() or not scene_path.is_dir():\n        print(f\"   ❌ Target scene assets directory could not be located on disk.\")\n        continue\n        \n    image_paths = sorted(list(scene_path.glob(\"*.jpg\")) + list(scene_path.glob(\"*.png\")))\n    if not image_paths:\n        image_paths = sorted(list((scene_path / \"images\").glob(\"*.jpg\")) + list((scene_path / \"images\").glob(\"*.png\")))\n        \n    if len(image_paths) < 2:\n        print(f\"   ❌ Inside target path, insufficient images detected.\")\n        continue\n        \n    print(f\"   Total source images successfully mapped: {len(image_paths)}\")\n    poses = get_all_camera_poses(image_paths, matches)\n    \n    if poses:\n        all_poses[scene_name] = poses\n        print(f\"   ✅ Matrix poses configured successfully for {len(poses)} items.\")\n\nprint(\"\\n\" + \"=\"*50)\nprint(f\"✅ Calculation complete! Valid pipeline poses mapped for {len(all_poses)} scenes.\")\nprint(\"=\"*50)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T08:50:37.189133Z","iopub.execute_input":"2026-06-13T08:50:37.189895Z","iopub.status.idle":"2026-06-13T08:50:57.979032Z","shell.execute_reply.started":"2026-06-13T08:50:37.189864Z","shell.execute_reply":"2026-06-13T08:50:57.978289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 9 & 10 (Strict Official 2025/2026 Format Overhaul)\nimport pandas as pd\nimport numpy as np\nfrom pathlib import Path\n\nprint(\"🚀 Starting Official Structural Alignment Module...\")\n\n# 1. PRECISE PATH DETECTION FOR IMC 2025/2026\nsample_sub_path = None\npossible_paths = [\n    Path(\"/kaggle/input/image-matching-challenge-2025-ongoing/sample_submission.csv\"),\n    Path(\"/kaggle/input/image-matching-challenge-2025/sample_submission.csv\"),\n    Path(\"/kaggle/input/image-matching-challenge-2024/sample_submission.csv\")\n]\n\nfor p in possible_paths:\n    if p.exists():\n        sample_sub_path = p\n        break\n\nif sample_sub_path is None:\n    # Look globally in input if paths vary dynamically\n    global_inputs = list(Path(\"/kaggle/input\").rglob(\"sample_submission.csv\"))\n    if global_inputs:\n        sample_sub_path = global_inputs[0]\n\n# 2. CORE TEMPLATE ENGINE (Bypasses all row-count mismatch errors)\nif sample_sub_path is not None:\n    print(f\"🎯 Found Official Test Template at: {sample_sub_path}\")\n    final_df = pd.read_csv(sample_sub_path)\n    print(f\"📊 Loaded {len(final_df)} required rows directly from Kaggle.\")\n    \n    # Check what columns Kaggle actually expects in this specific version\n    expected_cols = list(final_df.columns)\n    print(f\"📋 Expected Columns By Server: {expected_cols}\")\n    \n    # Initialize matrix columns with highly stable safe float layouts or NaNs\n    # We populate using our dictionary lookup if data exists, else clean floats\n    has_rot = \"rotation_matrix\" in final_df.columns\n    has_trans = \"translation_vector\" in final_df.columns\n    \n    rotations = []\n    translations = []\n    \n    for idx, row in final_df.iterrows():\n        img_name = row.get(\"image\", \"\")\n        # Fallback if image column is empty but image_id holds filename data\n        if pd.isna(img_name) or img_name == \"\":\n            img_name = Path(str(row.get(\"image_id\", \"\"))).name\n            \n        found_pose = None\n        # Dynamic search in our previously computed variables mapping dictionary\n        if 'all_poses' in globals():\n            for scene_k, poses_dict in all_poses.items():\n                for path_k, pose_v in poses_dict.items():\n                    if Path(path_k).name == img_name or img_name in str(path_k):\n                        found_pose = pose_v\n                        break\n                if found_pose: break\n        \n        # Inject computed metrics with exact 6-decimal string requirements\n        if found_pose and found_pose.get(\"R\") is not None:\n            R_flat = found_pose[\"R\"].flatten()\n            t_flat = found_pose[\"t\"].flatten()\n            r_str = \";\".join([f\"{x:.6f}\" for x in R_flat])\n            t_str = \";\".join([f\"{x:.6f}\" for x in t_flat])\n        else:\n            # If our offline SIFT did not map this dynamic hidden asset, use valid numeric formatting \n            # rather than nan strings if the validator requires initial seed coordinates\n            r_str = \"1.000000;0.000000;0.000000;0.000000;1.000000;0.000000;0.000000;0.000000;1.000000\"\n            t_str = \"0.000000;0.000000;0.000000\"\n            \n        rotations.append(r_str)\n        translations.append(t_str)\n        \n    if has_rot: final_df[\"rotation_matrix\"] = rotations\n    if has_trans: final_df[\"translation_vector\"] = translations\n\nelse:\n    # 3. EMERGENCY ROBUST FALLBACK (If sample file is not readable in interactive window)\n    print(\"⚠️ Sample submission not mapped in interactive memory space. Structuring dummy layout...\")\n    fallback_rows = []\n    \n    # Re-reading generated poses cleanly \n    if 'all_poses' in globals() and all_poses:\n        for scene_name, poses in all_poses.items():\n            scene_clean = scene_name.replace(\"train_\", \"\").replace(\"test_\", \"\").replace(\"validation_\", \"\")\n            for img_path, pose in poses.items():\n                img_filename = Path(img_path).name\n                fallback_rows.append({\n                    \"image_id\": f\"test_dataset__{scene_clean}__{img_filename}\", # Dynamic structural image_id standard\n                    \"dataset\": \"test_dataset\",\n                    \"scene\": scene_clean,\n                    \"image\": img_filename,\n                    \"rotation_matrix\": \";\".join([f\"{x:.6f}\" for x in pose[\"R\"].flatten()]),\n                    \"translation_vector\": \";\".join([f\"{x:.6f}\" for x in pose[\"t\"].flatten()])\n                })\n    \n    if not fallback_rows:\n        # Absolute safety loop seed\n        fallback_rows.append({\n            \"image_id\": \"dummy_id\", \"dataset\": \"test\", \"scene\": \"scene\", \"image\": \"img.png\",\n            \"rotation_matrix\": \"1.0;0.0;0.0;0.0;1.0;0.0;0.0;0.0;1.0\", \"translation_vector\": \"0.0;0.0;0.0\"\n        })\n    final_df = pd.DataFrame(fallback_rows)\n\n# Clean and enforce column order exactly matching whatever Kaggle wants\noutput_path = Path(\"/kaggle/working/submission.csv\")\nfinal_df.to_csv(output_path, index=False)\n\nprint(f\"\\n✅ FIXED SUBMISSION FILE WRITTEN SUCCESSFULLY TO: {output_path}\")\nprint(f\"📊 Rows Locked: {len(final_df)}\")\nprint(\"\\n📋 Validation Preview (Headers and Values Match Competition Instruction):\")\nprint(final_df.head(4).to_string())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T09:42:47.120530Z","iopub.execute_input":"2026-06-13T09:42:47.121286Z","iopub.status.idle":"2026-06-13T09:42:50.303311Z","shell.execute_reply.started":"2026-06-13T09:42:47.121253Z","shell.execute_reply":"2026-06-13T09:42:50.302580Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\n# Submission file ko load karein\ndf = pd.read_csv(\"/kaggle/working/submission.csv\")\n\n# Total entries (rows) check karein\nprint(f\"📊 Total Rows (Entries) in CSV: {len(df)}\")\nprint(f\"📋 Columns names: {list(df.columns)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-13T09:43:26.623108Z","iopub.execute_input":"2026-06-13T09:43:26.623873Z","iopub.status.idle":"2026-06-13T09:43:26.638962Z","shell.execute_reply.started":"2026-06-13T09:43:26.623827Z","shell.execute_reply":"2026-06-13T09:43:26.638001Z"}},"outputs":[],"execution_count":null}]}