{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":71885,"databundleVersionId":8143495,"sourceType":"competition"}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nfrom PIL import Image\nimport numpy as np","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:40.159147Z","iopub.execute_input":"2025-04-09T05:23:40.159354Z","iopub.status.idle":"2025-04-09T05:23:41.745005Z","shell.execute_reply.started":"2025-04-09T05:23:40.159335Z","shell.execute_reply":"2025-04-09T05:23:41.744321Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"categories = pd.read_csv(f\"/kaggle/input/image-matching-challenge-2024/train/categories.csv\")\ntrain_labels = pd.read_csv(f\"/kaggle/input/image-matching-challenge-2024/train/train_labels.csv\")\nsample_submission = pd.read_csv(f\"/kaggle/input/image-matching-challenge-2024/sample_submission.csv\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:41.746251Z","iopub.execute_input":"2025-04-09T05:23:41.746633Z","iopub.status.idle":"2025-04-09T05:23:41.805756Z","shell.execute_reply.started":"2025-04-09T05:23:41.746609Z","shell.execute_reply":"2025-04-09T05:23:41.805047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# List all images\nimage_dir = \"/kaggle/input/image-matching-challenge-2024/train/church/images/\"\nimage_files = os.listdir(image_dir)\nprint(len(image_files))\nprint(\"Example image:\", image_files[7])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:41.809297Z","iopub.execute_input":"2025-04-09T05:23:41.809539Z","iopub.status.idle":"2025-04-09T05:23:41.837103Z","shell.execute_reply.started":"2025-04-09T05:23:41.809508Z","shell.execute_reply":"2025-04-09T05:23:41.836446Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom PIL import Image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:41.838497Z","iopub.execute_input":"2025-04-09T05:23:41.838737Z","iopub.status.idle":"2025-04-09T05:23:41.841893Z","shell.execute_reply.started":"2025-04-09T05:23:41.838710Z","shell.execute_reply":"2025-04-09T05:23:41.841109Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_image(image_dir, file):\n    img = Image.open(f\"{image_dir}{file}\")\n    plt.imshow(img)\n    plt.axis('off')  \n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:41.842798Z","iopub.execute_input":"2025-04-09T05:23:41.843047Z","iopub.status.idle":"2025-04-09T05:23:41.859121Z","shell.execute_reply.started":"2025-04-09T05:23:41.843028Z","shell.execute_reply":"2025-04-09T05:23:41.858498Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_dir = \"/kaggle/input/image-matching-challenge-2024/train/church/images/\"\nload_image(image_dir, \"00001.png\")\nload_image(image_dir, \"00002.png\")\nload_image(image_dir, \"00003.png\")\nload_image(image_dir, \"00004.png\")\n\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:41.859888Z","iopub.execute_input":"2025-04-09T05:23:41.860170Z","iopub.status.idle":"2025-04-09T05:23:43.007102Z","shell.execute_reply.started":"2025-04-09T05:23:41.860139Z","shell.execute_reply":"2025-04-09T05:23:43.006229Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom PIL import Image\nimport numpy as np\n\n# Path to the image directory\nimage_dir = \"/kaggle/input/image-matching-challenge-2024/train/church/images\"\n\n# List to hold all image matrices\nimage_matrices = []\n\nimage_files = sorted(os.listdir(image_dir))\n\nfor file_name in image_files:\n    if file_name.endswith(\".png\"):\n        img_path = os.path.join(image_dir, file_name)\n        img = Image.open(img_path).convert('RGB').resize((256, 256))\n        img_array = np.array(img)\n        image_matrices.append(img_array)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:23:43.007978Z","iopub.execute_input":"2025-04-09T05:23:43.008320Z","iopub.status.idle":"2025-04-09T05:23:49.660907Z","shell.execute_reply.started":"2025-04-09T05:23:43.008282Z","shell.execute_reply":"2025-04-09T05:23:49.660231Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image_matrices[0].shape\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:10.087868Z","iopub.execute_input":"2025-04-09T05:25:10.088177Z","iopub.status.idle":"2025-04-09T05:25:10.093148Z","shell.execute_reply.started":"2025-04-09T05:25:10.088155Z","shell.execute_reply":"2025-04-09T05:25:10.092311Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\n\n# Example with SIFT\nsift = cv2.SIFT_create()\nkp1, des1 = sift.detectAndCompute(image_matrices[0], None)\nkp2, des2 = sift.detectAndCompute(image_matrices[1], None)\n\n# Brute Force Matcher\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\n# Draw matches\nmatched_img = cv2.drawMatchesKnn(image_matrices[0], kp1, image_matrices[1], kp2, good_matches, None, flags=2)\nplt.imshow(matched_img)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:10.387421Z","iopub.execute_input":"2025-04-09T05:25:10.387691Z","iopub.status.idle":"2025-04-09T05:25:11.816000Z","shell.execute_reply.started":"2025-04-09T05:25:10.387670Z","shell.execute_reply":"2025-04-09T05:25:11.815111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"N = 20  \nsubset_images = image_matrices[:N]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:14.257740Z","iopub.execute_input":"2025-04-09T05:25:14.258078Z","iopub.status.idle":"2025-04-09T05:25:14.261746Z","shell.execute_reply.started":"2025-04-09T05:25:14.258051Z","shell.execute_reply":"2025-04-09T05:25:14.261075Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nfrom tqdm import tqdm\nimport numpy as np\nimport itertools\n\n# Initialize SIFT\nsift = cv2.SIFT_create()\n\n# Brute-Force Matcher\nbf = cv2.BFMatcher()\n\n# Dictionary to store similarity scores\nsimilarity_scores = {}\n\n# Iterate through all unique pairs\nfor i, j in tqdm(itertools.combinations(range(len(subset_images)), 2), total=(len(subset_images)*(len(subset_images)-1))//2):\n    img1 = subset_images[i]\n    img2 = subset_images[j]\n    \n    # Convert to grayscale (SIFT works on single channel)\n    gray1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)\n    gray2 = cv2.cvtColor(img2, cv2.COLOR_RGB2GRAY)\n    \n    # Detect and compute keypoints/descriptors\n    kp1, des1 = sift.detectAndCompute(gray1, None)\n    kp2, des2 = sift.detectAndCompute(gray2, None)\n    \n    if des1 is None or des2 is None:\n        score = 0\n    else:\n        matches = bf.knnMatch(des1, des2, k=2)\n\n        # Apply Lowe's ratio test\n        good_matches = [m for m, n in matches if m.distance < 0.75 * n.distance]\n\n        # Similarity score = number of good matches\n        score = len(good_matches)\n\n    similarity_scores[(i, j)] = score\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:14.492519Z","iopub.execute_input":"2025-04-09T05:25:14.492747Z","iopub.status.idle":"2025-04-09T05:25:22.539479Z","shell.execute_reply.started":"2025-04-09T05:25:14.492727Z","shell.execute_reply":"2025-04-09T05:25:22.538661Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"top_matches = sorted(similarity_scores.items(), key=lambda x: x[1], reverse=True)\nprint(top_matches[:10])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:22.540722Z","iopub.execute_input":"2025-04-09T05:25:22.541022Z","iopub.status.idle":"2025-04-09T05:25:22.546251Z","shell.execute_reply.started":"2025-04-09T05:25:22.540994Z","shell.execute_reply":"2025-04-09T05:25:22.545228Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"categories","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:22.548039Z","iopub.execute_input":"2025-04-09T05:25:22.548313Z","iopub.status.idle":"2025-04-09T05:25:22.591039Z","shell.execute_reply.started":"2025-04-09T05:25:22.548286Z","shell.execute_reply":"2025-04-09T05:25:22.590157Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:22.592343Z","iopub.execute_input":"2025-04-09T05:25:22.592614Z","iopub.status.idle":"2025-04-09T05:25:22.606763Z","shell.execute_reply.started":"2025-04-09T05:25:22.592593Z","shell.execute_reply":"2025-04-09T05:25:22.605831Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Rotation_matrix {train_labels.loc[0, 'rotation_matrix']}\")\nprint(f\"Translation vector {train_labels.loc[0, 'translation_vector']}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:22.607637Z","iopub.execute_input":"2025-04-09T05:25:22.607963Z","iopub.status.idle":"2025-04-09T05:25:22.627195Z","shell.execute_reply.started":"2025-04-09T05:25:22.607933Z","shell.execute_reply":"2025-04-09T05:25:22.626413Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_submission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:22.627986Z","iopub.execute_input":"2025-04-09T05:25:22.628324Z","iopub.status.idle":"2025-04-09T05:25:22.654414Z","shell.execute_reply.started":"2025-04-09T05:25:22.628296Z","shell.execute_reply":"2025-04-09T05:25:22.653592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_labels.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:22.655265Z","iopub.execute_input":"2025-04-09T05:25:22.655555Z","iopub.status.idle":"2025-04-09T05:25:22.689345Z","shell.execute_reply.started":"2025-04-09T05:25:22.655528Z","shell.execute_reply":"2025-04-09T05:25:22.688406Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_labels_subset = train_labels.loc[:500, :]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:26.587949Z","iopub.execute_input":"2025-04-09T05:25:26.588377Z","iopub.status.idle":"2025-04-09T05:25:26.593519Z","shell.execute_reply.started":"2025-04-09T05:25:26.588338Z","shell.execute_reply":"2025-04-09T05:25:26.592350Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Constructing a dataset of a subset of the data, loading in corresponding images based on the train_labels_subset","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset\nimport os\nfrom PIL import Image\nimport numpy as np\nimport pandas as pd\n\nclass ImagePoseDataset(Dataset):\n    def __init__(self, dataframe, image_base_path, transform=None):\n        \"\"\"\n        Args:\n            dataframe (pd.DataFrame): A subset of train_labels.csv.\n            image_base_path (str): Base path to the /train folder.\n            transform (callable, optional): Optional transform to be applied on a sample image.\n        \"\"\"\n        self.df = dataframe.reset_index(drop=True)\n        self.image_base_path = image_base_path\n        self.transform = transform\n\n        # Optional: prefilter valid rows\n        self.valid_rows = []\n        for _, row in self.df.iterrows():\n            image_path = os.path.join(image_base_path, row['dataset'], \"images\", row['image_name'])\n            try:\n                _ = np.array(row['rotation_matrix'].split(';'), dtype=np.float64).reshape(3, 3)\n                _ = np.array(row['translation_vector'].split(';'), dtype=np.float64).reshape(3, 1)\n                if os.path.exists(image_path):\n                    self.valid_rows.append(row)\n            except:\n                continue\n\n    def __len__(self):\n        return len(self.valid_rows)\n\n    def __getitem__(self, idx):\n        row = self.valid_rows[idx]\n        image_path = os.path.join(self.image_base_path, row['dataset'], \"images\", row['image_name'])\n\n        # Load image\n        img = Image.open(image_path).convert(\"RGB\")\n        if self.transform:\n            img = self.transform(img)\n        else:\n            img = torch.from_numpy(np.array(img)).permute(2, 0, 1).float() / 255.0  # [3, H, W] normalized\n\n        # Rotation and translation\n        rotation_matrix = torch.tensor(\n            np.array(row['rotation_matrix'].split(';'), dtype=np.float32).reshape(3, 3)\n        )\n        translation_vector = torch.tensor(\n            np.array(row['translation_vector'].split(';'), dtype=np.float32).reshape(3, 1)\n        )\n\n        return {\n            \"image\": img,\n            \"rotation_matrix\": rotation_matrix,\n            \"translation_vector\": translation_vector,\n            \"image_name\": row['image_name'],\n            \"scene\": row['scene'],\n            \"dataset\": row['dataset']\n        }\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:29.597781Z","iopub.execute_input":"2025-04-09T05:25:29.598079Z","iopub.status.idle":"2025-04-09T05:25:35.575400Z","shell.execute_reply.started":"2025-04-09T05:25:29.598055Z","shell.execute_reply":"2025-04-09T05:25:35.574453Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Normalizing the data- to the same size","metadata":{}},{"cell_type":"code","source":"from torchvision import transforms\n\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor()\n])\n\nimage_base_path = \"/kaggle/input/image-matching-challenge-2024/train\"\ndataset = ImagePoseDataset(train_labels_subset, image_base_path, transform=transform)\n\nsample = dataset[0]\nprint(sample['image'].shape)  \nprint(sample['rotation_matrix'])\nprint(sample['translation_vector'])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:35.576651Z","iopub.execute_input":"2025-04-09T05:25:35.577167Z","iopub.status.idle":"2025-04-09T05:25:41.169924Z","shell.execute_reply.started":"2025-04-09T05:25:35.577135Z","shell.execute_reply":"2025-04-09T05:25:41.169143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Number of samples in the dataset: {len(dataset)}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:41.171156Z","iopub.execute_input":"2025-04-09T05:25:41.171537Z","iopub.status.idle":"2025-04-09T05:25:41.175690Z","shell.execute_reply.started":"2025-04-09T05:25:41.171515Z","shell.execute_reply":"2025-04-09T05:25:41.174907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample = dataset[0]\nprint(\"Image shape:\", sample['image'].shape)  # [C, H, W]\nprint(\"Rotation matrix shape:\", sample['rotation_matrix'].shape)  # [3, 3]\nprint(\"Translation vector shape:\", sample['translation_vector'].shape)  # [3, 1]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:41.176733Z","iopub.execute_input":"2025-04-09T05:25:41.177026Z","iopub.status.idle":"2025-04-09T05:25:41.800995Z","shell.execute_reply.started":"2025-04-09T05:25:41.176998Z","shell.execute_reply":"2025-04-09T05:25:41.800196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import random_split\n\n# Set lengths\ntotal_len = len(dataset)\ntrain_len = int(0.8 * total_len)\nval_len = total_len - train_len\n\n# Random split\ntrain_dataset, val_dataset = random_split(dataset, [train_len, val_len])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:41.801743Z","iopub.execute_input":"2025-04-09T05:25:41.801967Z","iopub.status.idle":"2025-04-09T05:25:41.814653Z","shell.execute_reply.started":"2025-04-09T05:25:41.801949Z","shell.execute_reply":"2025-04-09T05:25:41.814014Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training a simple CNN regression model to get predictions for the rotation matrix and the translation vector","metadata":{}},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass PoseRegressor(nn.Module):\n    def __init__(self):\n        super(PoseRegressor, self).__init__()\n        self.backbone = nn.Sequential(\n            nn.Conv2d(3, 16, kernel_size=3, stride=2, padding=1),  # [B, 16, 112, 112]\n            nn.ReLU(),\n            nn.Conv2d(16, 32, kernel_size=3, stride=2, padding=1),  # [B, 32, 56, 56]\n            nn.ReLU(),\n            nn.Conv2d(32, 64, kernel_size=3, stride=2, padding=1),  # [B, 64, 28, 28]\n            nn.ReLU(),\n            nn.AdaptiveAvgPool2d((1, 1))  # [B, 64, 1, 1]\n        )\n        self.fc = nn.Flatten()\n        self.fc_rotation = nn.Linear(64, 9)   # 3x3 matrix\n        self.fc_translation = nn.Linear(64, 3)  # 3x1 vector\n\n    def forward(self, x):\n        x = self.backbone(x)\n        x = self.fc(x)\n        rot = self.fc_rotation(x)\n        trans = self.fc_translation(x)\n        rot = rot.view(-1, 3, 3)\n        trans = trans.view(-1, 3, 1)\n        return rot, trans\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:48.908094Z","iopub.execute_input":"2025-04-09T05:25:48.908488Z","iopub.status.idle":"2025-04-09T05:25:48.917318Z","shell.execute_reply.started":"2025-04-09T05:25:48.908455Z","shell.execute_reply":"2025-04-09T05:25:48.916202Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Using the camera center loss as given in the competition overview\n","metadata":{}},{"cell_type":"code","source":"def camera_center_loss(pred_R, pred_T, true_R, true_T):\n    # Compute camera centers: C = -R^T @ T\n    pred_C = -torch.matmul(pred_R.transpose(1, 2), pred_T)  # [B, 3, 1]\n    true_C = -torch.matmul(true_R.transpose(1, 2), true_T)  # [B, 3, 1]\n\n    return F.mse_loss(pred_C, true_C)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:26:33.330800Z","iopub.execute_input":"2025-04-09T05:26:33.331132Z","iopub.status.idle":"2025-04-09T05:26:33.335454Z","shell.execute_reply.started":"2025-04-09T05:26:33.331103Z","shell.execute_reply":"2025-04-09T05:26:33.334465Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from torch.utils.data import DataLoader\n\ntrain_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=16)\n\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\nmodel = PoseRegressor().to(device)\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\ncriterion = nn.MSELoss()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:25:49.172990Z","iopub.execute_input":"2025-04-09T05:25:49.173297Z","iopub.status.idle":"2025-04-09T05:25:49.513896Z","shell.execute_reply.started":"2025-04-09T05:25:49.173270Z","shell.execute_reply":"2025-04-09T05:25:49.512994Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training the model","metadata":{}},{"cell_type":"code","source":"from tqdm import tqdm\n\nepochs = 10\n\nfor epoch in range(epochs):\n    model.train()\n    total_loss = 0\n\n    loop = tqdm(train_loader, desc=f\"Epoch {epoch+1}/{epochs}\", leave=False)\n\n    for batch in loop: \n        imgs = batch['image'].to(device)\n        true_R = batch['rotation_matrix'].to(device)\n        true_T = batch['translation_vector'].to(device)\n    \n        pred_R, pred_T = model(imgs)\n    \n        loss = camera_center_loss(pred_R, pred_T, true_R, true_T)\n    \n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n        # Update progress bar\n        loop.set_postfix({\n            \"loss\": f\"{loss.item():.4f}\"\n        })\n\n    print(f\"Epoch {epoch+1} | Avg Train Loss: {total_loss/len(train_loader):.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:30:00.293191Z","iopub.execute_input":"2025-04-09T05:30:00.293469Z","iopub.status.idle":"2025-04-09T05:31:54.727401Z","shell.execute_reply.started":"2025-04-09T05:30:00.293447Z","shell.execute_reply":"2025-04-09T05:31:54.726525Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Checking the model accuracy and loss","metadata":{}},{"cell_type":"code","source":"model.eval()\nval_loss = 0\nprint_limit = 3  \n\nwith torch.no_grad():\n    val_loop = tqdm(val_loader, desc=\"Validating\", leave=False)\n\n    shown = 0\n    for batch in val_loop:\n        imgs = batch['image'].to(device)\n        true_R = batch['rotation_matrix'].to(device)\n        true_T = batch['translation_vector'].to(device)\n\n        pred_R, pred_T = model(imgs)\n        loss = camera_center_loss(pred_R, pred_T, true_R, true_T)\n        val_loss += loss.item()\n\n        val_loop.set_postfix({\"loss\": f\"{loss.item():.4f}\"})\n\n        if shown < print_limit:\n            for i in range(min(len(imgs), print_limit - shown)):\n                print(f\"\\nSample {shown + 1}\")\n                print(\"Ground Truth Rotation Matrix:\\n\", true_R[i].cpu().numpy())\n                print(\"Predicted Rotation Matrix:\\n\", pred_R[i].cpu().numpy())\n\n                print(\"Ground Truth Translation Vector:\\n\", true_T[i].cpu().numpy().flatten())\n                print(\"Predicted Translation Vector:\\n\", pred_T[i].cpu().numpy().flatten())\n                \n                shown += 1\n            if shown >= print_limit:\n                break\n\nprint(f\"\\nFinal Validation Loss (Camera Center Based): {val_loss / len(val_loader):.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-09T05:35:04.491600Z","iopub.execute_input":"2025-04-09T05:35:04.491957Z","iopub.status.idle":"2025-04-09T05:35:06.792732Z","shell.execute_reply.started":"2025-04-09T05:35:04.491928Z","shell.execute_reply":"2025-04-09T05:35:06.791983Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### The model obtained is not very accurate- if I had more time then I could have used a larger model, as it would take a long time to train, even with powerful GPUs","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}