{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":71885,"databundleVersionId":8143495,"sourceType":"competition"},{"sourceId":7884485,"sourceType":"datasetVersion","datasetId":4628051},{"sourceId":174129945,"sourceType":"kernelVersion"}],"dockerImageVersionId":30698,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!python -m pip install --no-deps /kaggle/input/dependencies-imc/safetensors/safetensors-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n!python -m pip install --no-index --find-links=/kaggle/input/dependencies-imc/transformers/ transformers > /dev/null\n!python -m pip install  --no-deps /kaggle/input/imc2024-packages-lightglue-rerun-kornia/lightglue-0.0-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2024-05-15T13:34:48.901934Z","iopub.execute_input":"2024-05-15T13:34:48.902307Z","iopub.status.idle":"2024-05-15T13:35:06.611930Z","shell.execute_reply.started":"2024-05-15T13:34:48.902276Z","shell.execute_reply":"2024-05-15T13:35:06.610661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport kornia as K\nimport kornia.feature as KF\nfrom PIL import Image\nfrom tqdm.auto import tqdm\nimport torch\nfrom matplotlib import pyplot as plt\nimport torchvision.transforms as TT\nfrom lightglue import match_pair\nfrom lightglue import ALIKED, SuperPoint, DoGHardNet, LightGlue\nfrom lightglue.utils import load_image, rbd","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-05-15T13:42:20.881752Z","iopub.execute_input":"2024-05-15T13:42:20.882129Z","iopub.status.idle":"2024-05-15T13:42:20.887939Z","shell.execute_reply.started":"2024-05-15T13:42:20.882097Z","shell.execute_reply":"2024-05-15T13:42:20.886924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_torch_image(fname, device=torch.device('cpu')):\n    img = K.io.load_image(fname, K.io.ImageLoadType.RGB32, device=device)[None, ...]\n    return img\n\ndef tensor2image(img):\n    arr = torch.permute(img, (0,2,3,1))[0].numpy()*255\n    return arr","metadata":{"execution":{"iopub.status.busy":"2024-05-15T13:42:23.530715Z","iopub.execute_input":"2024-05-15T13:42:23.531084Z","iopub.status.idle":"2024-05-15T13:42:23.536644Z","shell.execute_reply.started":"2024-05-15T13:42:23.531054Z","shell.execute_reply":"2024-05-15T13:42:23.535768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_name = \"aliked\"\nnum_features = -1\ndetection_threshold = 0.01\nresize_to = 512\ndevice = torch.device(\"cuda\")","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extractor / Matcher\ndict_model = {\n    \"aliked\" : ALIKED,\n    \"superpoint\" : SuperPoint,\n    \"doghardnet\" : DoGHardNet,\n}\nextractor_class = dict_model[model_name]\n\ndtype = torch.float32\nextractor = extractor_class(\n    max_num_keypoints=num_features, detection_threshold=detection_threshold, resize=resize_to\n).eval().to(device, dtype)\n\nlg_matcher = KF.LightGlueMatcher(\n    model_name, \n    {\n        \"width_confidence\": -1,\n        \"depth_confidence\": -1,\n        \"mp\": True if 'cuda' in str(device) else False\n    }\n).eval().to(device)","metadata":{"execution":{"iopub.status.busy":"2024-05-15T13:35:13.499010Z","iopub.execute_input":"2024-05-15T13:35:13.499356Z","iopub.status.idle":"2024-05-15T13:35:16.826684Z","shell.execute_reply.started":"2024-05-15T13:35:13.499323Z","shell.execute_reply":"2024-05-15T13:35:16.825751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Main","metadata":{}},{"cell_type":"code","source":"files = [\n    \"/kaggle/input/image-matching-challenge-2024/test/church/images/00001.png\",\n    \"/kaggle/input/image-matching-challenge-2024/train/dioscuri/images/3dom_fbk_img_1512.png\",\n    \"/kaggle/input/image-matching-challenge-2024/train/multi-temporal-temple-baalshamin/images/182z.png\",\n    \"/kaggle/input/image-matching-challenge-2024/train/pond/images/00008.png\",\n    \"/kaggle/input/image-matching-challenge-2024/train/lizard/images/00006.png\",\n]\n\nfor file in files:\n    print(file)\n    img = load_torch_image(file)\n    display(Image.fromarray(tensor2image(img).astype(np.uint8)).resize((256,256)))\n    \n    angles = []\n    num_keypoints = []\n    num_matches = []\n    for rotk in tqdm(range(72)):\n        angle = 5 * rotk - 180\n        img_rot = TT.functional.rotate(img, angle, center=[img.shape[3]//2+0.5, img.shape[2]//2+0.5])\n        # display(Image.fromarray(tensor2image(img_rot).astype(np.uint8)).resize((256,256)))\n\n        with torch.inference_mode():\n            feats1 = extractor.extract(img.to(device))\n            feats2 = extractor.extract(img_rot.to(device))\n            kpts1 = feats1['keypoints'].reshape(-1, 2).detach()\n            descs1 = feats1['descriptors'].reshape(len(kpts1), -1).detach()\n            kpts2 = feats2['keypoints'].reshape(-1, 2).detach()\n            descs2 = feats2['descriptors'].reshape(len(kpts2), -1).detach()\n            dists, idxs = lg_matcher(descs1,\n                                     descs2,\n                                     KF.laf_from_center_scale_ori(kpts1[None]),\n                                     KF.laf_from_center_scale_ori(kpts2[None]))\n        n_matches = len(idxs)\n        kpts1 = kpts1[idxs[:,0], :].cpu().numpy().reshape(-1, 2).astype(np.float32)\n        kpts2 = kpts2[idxs[:,1], :].cpu().numpy().reshape(-1, 2).astype(np.float32)\n\n        angles.append(angle)\n        num_keypoints.append(descs2.shape[0])\n        num_matches.append(kpts1.shape[0])\n        \n    plt.scatter(angles, num_matches)\n    plt.xlabel(\"angle / degree\")\n    plt.ylabel(\"num of matches / points\")\n    plt.xticks(np.arange(-180, 180, 30))\n    plt.grid()\n    plt.show()\n    \n    plt.scatter(angles, np.array(num_matches) / np.array(num_keypoints) )\n    plt.xlabel(\"angle / degree\")\n    plt.ylabel(\"num of matches / num of keypoints( on rotated image)\")\n    plt.xticks(np.arange(-180, 180, 30))\n    plt.grid()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-05-15T13:48:57.744027Z","iopub.execute_input":"2024-05-15T13:48:57.744801Z","iopub.status.idle":"2024-05-15T13:51:06.984008Z","shell.execute_reply.started":"2024-05-15T13:48:57.744767Z","shell.execute_reply":"2024-05-15T13:51:06.983058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"raw","source":"","metadata":{}}]}