{"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":"none","dataSources":[{"sourceId":91498,"databundleVersionId":11655853,"sourceType":"competition"}],"dockerImageVersionId":30919,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Published on April 01, 2024. By Prata, Marília (mpwolke).","metadata":{}},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n%matplotlib inline\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport warnings\nwarnings.simplefilter(action='ignore', category=FutureWarning)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:40:36.325073Z","iopub.execute_input":"2025-04-01T23:40:36.325480Z","iopub.status.idle":"2025-04-01T23:40:41.765177Z","shell.execute_reply.started":"2025-04-01T23:40:36.325452Z","shell.execute_reply":"2025-04-01T23:40:41.760996Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"_kg_hide-output":true,"_kg_hide-input":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"![](https://media.tenor.com/Pr-f-ix7DicAAAAM/et-home.gif)","metadata":{}},{"cell_type":"markdown","source":"## Competition Citation\n\n@misc{image-matching-challenge-2025,\n\n    author = {Fabio Bellavia and Jiri Matas and Dmytro Mishkin and Luca Morelli and Fabio Remondino and Amy Tabb and Eduard Trulls and Kwang Moo Yi and Sohier Dane and Addison Howard and María Cruz},\n    title = {Image Matching Challenge 2025},\n    \n    year = {2025},\n    \n    howpublished = {\\url{https://kaggle.com/competitions/image-matching-challenge-2025}},\n    \n    note = {Kaggle}\n}","metadata":{}},{"cell_type":"code","source":"labels = pd.read_csv('/kaggle/input/image-matching-challenge-2025/train_labels.csv')\nthresh = pd.read_csv('/kaggle/input/image-matching-challenge-2025/train_thresholds.csv')\nsub = pd.read_csv('/kaggle/input/image-matching-challenge-2025/sample_submission.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:40:51.510729Z","iopub.execute_input":"2025-04-01T23:40:51.511180Z","iopub.status.idle":"2025-04-01T23:40:51.584787Z","shell.execute_reply.started":"2025-04-01T23:40:51.511113Z","shell.execute_reply":"2025-04-01T23:40:51.584165Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels.tail(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:40:56.437754Z","iopub.execute_input":"2025-04-01T23:40:56.438072Z","iopub.status.idle":"2025-04-01T23:40:56.465274Z","shell.execute_reply.started":"2025-04-01T23:40:56.438041Z","shell.execute_reply":"2025-04-01T23:40:56.464449Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### ETs, more ETs and another_ET. Dioscuri is back!","metadata":{}},{"cell_type":"code","source":"thresh.head(13)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:41:01.593692Z","iopub.execute_input":"2025-04-01T23:41:01.593974Z","iopub.status.idle":"2025-04-01T23:41:01.602701Z","shell.execute_reply.started":"2025-04-01T23:41:01.593951Z","shell.execute_reply":"2025-04-01T23:41:01.601696Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### ETs_another_et_another-et   on submission","metadata":{}},{"cell_type":"code","source":"sub.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:41:06.408168Z","iopub.execute_input":"2025-04-01T23:41:06.408464Z","iopub.status.idle":"2025-04-01T23:41:06.417730Z","shell.execute_reply.started":"2025-04-01T23:41:06.408436Z","shell.execute_reply":"2025-04-01T23:41:06.416638Z"},"_kg_hide-input":false},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Import Libraries","metadata":{}},{"cell_type":"code","source":"import cv2\n\nfrom glob import glob\nfrom pathlib import Path\nfrom time import time","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:41:39.446269Z","iopub.execute_input":"2025-04-01T23:41:39.446564Z","iopub.status.idle":"2025-04-01T23:41:39.450536Z","shell.execute_reply.started":"2025-04-01T23:41:39.446542Z","shell.execute_reply":"2025-04-01T23:41:39.449600Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### train file ETs","metadata":{}},{"cell_type":"code","source":"#MPwolke https://www.kaggle.com/code/mpwolke/rijksmuseum-augmentation/notebook\n\ndef plotImages(swissroads,directory):\n    print(swissroads)\n    multipleImages = glob(directory)\n    plt.rcParams['figure.figsize'] = (15, 15)\n    plt.subplots_adjust(wspace=0, hspace=0)\n    i_ = 0\n    for l in multipleImages[:12]:\n        im = cv2.imread(l)\n        im = cv2.resize(im, (128, 128)) \n        plt.subplot(5, 5, i_+1) #.set_title(l)\n        plt.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB)); plt.axis('off')\n        i_ += 1\n        \n        \nplotImages(\"ETs train images\",\"../input/image-matching-challenge-2025/train/ETs/**\")","metadata":{"trusted":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2025-04-01T23:41:44.649314Z","iopub.execute_input":"2025-04-01T23:41:44.649630Z","iopub.status.idle":"2025-04-01T23:41:45.867395Z","shell.execute_reply.started":"2025-04-01T23:41:44.649603Z","shell.execute_reply":"2025-04-01T23:41:45.866458Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### test file ETs ","metadata":{}},{"cell_type":"code","source":"#MPwolke https://www.kaggle.com/code/mpwolke/rijksmuseum-augmentation/notebook\n\ndef plotImages(swissroads,directory):\n    print(swissroads)\n    multipleImages = glob(directory)\n    plt.rcParams['figure.figsize'] = (15, 15)\n    plt.subplots_adjust(wspace=0, hspace=0)\n    i_ = 0\n    for l in multipleImages[:13]:\n        im = cv2.imread(l)\n        im = cv2.resize(im, (128, 128)) \n        plt.subplot(5, 5, i_+1) #.set_title(l)\n        plt.imshow(cv2.cvtColor(im, cv2.COLOR_BGR2RGB)); plt.axis('off')\n        i_ += 1\n        \n        \nplotImages(\"ETs test images\",\"../input/image-matching-challenge-2025/test/ETs/**\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:41:52.044753Z","iopub.execute_input":"2025-04-01T23:41:52.045036Z","iopub.status.idle":"2025-04-01T23:41:53.248259Z","shell.execute_reply.started":"2025-04-01T23:41:52.045013Z","shell.execute_reply":"2025-04-01T23:41:53.247058Z"},"_kg_hide-input":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Create image generator\ntrain_generator = ImageDataGenerator(\n    rescale=1 / 255, horizontal_flip=True, rotation_range=5, validation_split=0.2\n)\ntest_generator = ImageDataGenerator(rescale=1. / 255)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:41:58.985046Z","iopub.execute_input":"2025-04-01T23:41:58.985394Z","iopub.status.idle":"2025-04-01T23:42:16.658430Z","shell.execute_reply.started":"2025-04-01T23:41:58.985368Z","shell.execute_reply":"2025-04-01T23:42:16.657772Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Train/test","metadata":{}},{"cell_type":"code","source":"# Train, validation and test sets\ntrainset = train_generator.flow_from_directory(\n    os.path.join(\"../input/image-matching-challenge-2025/\", \"train\"),\n    batch_size=32,\n    target_size=(32, 32),\n    shuffle=True,\n    subset=\"training\",\n)\nvalidset = train_generator.flow_from_directory(\n    os.path.join(\"../input/image-matching-challenge-2025/\", \"train\"),\n    batch_size=32,\n    target_size=(32, 32),\n    shuffle=False,\n    subset=\"validation\",\n)\ntestset = test_generator.flow_from_directory(\n    os.path.join(\"../input/image-matching-challenge-2025/\", \"test\"), batch_size=32, target_size=(32, 32), shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:42:32.940938Z","iopub.execute_input":"2025-04-01T23:42:32.941609Z","iopub.status.idle":"2025-04-01T23:42:34.333523Z","shell.execute_reply.started":"2025-04-01T23:42:32.941574Z","shell.execute_reply":"2025-04-01T23:42:34.332613Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### More ETs","metadata":{}},{"cell_type":"code","source":"trainset.filenames[:5]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:42:40.437338Z","iopub.execute_input":"2025-04-01T23:42:40.437652Z","iopub.status.idle":"2025-04-01T23:42:40.442995Z","shell.execute_reply.started":"2025-04-01T23:42:40.437624Z","shell.execute_reply":"2025-04-01T23:42:40.442191Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### And ETs/another_et_another","metadata":{}},{"cell_type":"code","source":"validset.filenames[:4]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:42:45.110753Z","iopub.execute_input":"2025-04-01T23:42:45.111058Z","iopub.status.idle":"2025-04-01T23:42:45.116633Z","shell.execute_reply.started":"2025-04-01T23:42:45.111033Z","shell.execute_reply":"2025-04-01T23:42:45.115745Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Our class names","metadata":{}},{"cell_type":"code","source":"trainset.class_indices","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:42:50.245190Z","iopub.execute_input":"2025-04-01T23:42:50.245495Z","iopub.status.idle":"2025-04-01T23:42:50.250745Z","shell.execute_reply.started":"2025-04-01T23:42:50.245467Z","shell.execute_reply":"2025-04-01T23:42:50.249963Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"import tensorflow.keras as keras\n\n# Convolutional Network\nmodel = keras.Sequential()\nmodel.add(keras.layers.Conv2D(filters=64, kernel_size=5, strides=2, activation=\"relu\",\n                              input_shape=(32, 32, 3)))\nmodel.add(keras.layers.MaxPool2D(pool_size=2))\nmodel.add(keras.layers.Conv2D(filters=64, kernel_size=3, strides=1, activation=\"relu\"))\nmodel.add(keras.layers.MaxPool2D(pool_size=2))\nmodel.add(keras.layers.Flatten())\nmodel.add(keras.layers.Dense(units=trainset.num_classes, activation=\"softmax\"))\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:43:04.280915Z","iopub.execute_input":"2025-04-01T23:43:04.281252Z","iopub.status.idle":"2025-04-01T23:43:04.337995Z","shell.execute_reply.started":"2025-04-01T23:43:04.281223Z","shell.execute_reply":"2025-04-01T23:43:04.337342Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Compile the model\nmodel.compile(optimizer=keras.optimizers.Adam(),\n              loss=\"categorical_crossentropy\",\n              metrics=[\"acc\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:43:09.735688Z","iopub.execute_input":"2025-04-01T23:43:09.736002Z","iopub.status.idle":"2025-04-01T23:43:09.749168Z","shell.execute_reply.started":"2025-04-01T23:43:09.735972Z","shell.execute_reply":"2025-04-01T23:43:09.748346Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Callbacks","metadata":{}},{"cell_type":"code","source":"# End training when accuracy stops improving (optional)\nearly_stopping = keras.callbacks.EarlyStopping(monitor=\"val_loss\", patience=6)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:43:14.198969Z","iopub.execute_input":"2025-04-01T23:43:14.199268Z","iopub.status.idle":"2025-04-01T23:43:14.203097Z","shell.execute_reply.started":"2025-04-01T23:43:14.199244Z","shell.execute_reply":"2025-04-01T23:43:14.202207Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Epochs. GPU is ON!","metadata":{}},{"cell_type":"code","source":"# Train model\nhistory = model.fit(\n    trainset, validation_data=validset, epochs=10, callbacks=[early_stopping] #Original Epochs 100\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-01T23:43:18.942560Z","iopub.execute_input":"2025-04-01T23:43:18.942890Z","iopub.status.idle":"2025-04-02T00:04:09.816716Z","shell.execute_reply.started":"2025-04-01T23:43:18.942860Z","shell.execute_reply":"2025-04-02T00:04:09.815994Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### My ETs Loss and Accuracy : )","metadata":{}},{"cell_type":"code","source":"%matplotlib inline\nimport matplotlib.pyplot as plt\n\nfig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12, 4))\n\n# Plot loss values\nax1.set_title(\"loss: {:.4f}\".format(history.history[\"val_loss\"][-1]))\nax1.plot(history.history[\"val_loss\"], label=\"validation\")\nax1.plot(history.history[\"loss\"], label=\"training\")\nax1.legend()\n\n# plot accuracy values\nax2.set_title(\"accuracy: {:.2f}%\".format(history.history[\"val_acc\"][-1] * 100))\nax2.plot(history.history[\"val_acc\"], label=\"validation\")\nax2.plot(history.history[\"acc\"], label=\"training\")\nax2.legend()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-02T00:04:14.978537Z","iopub.execute_input":"2025-04-02T00:04:14.978836Z","iopub.status.idle":"2025-04-02T00:04:15.360507Z","shell.execute_reply.started":"2025-04-02T00:04:14.978812Z","shell.execute_reply":"2025-04-02T00:04:15.359638Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_preds = model.predict(testset)\nprint(\"Predictions:\", test_preds.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-02T00:04:21.724269Z","iopub.execute_input":"2025-04-02T00:04:21.724569Z","iopub.status.idle":"2025-04-02T00:04:28.751009Z","shell.execute_reply.started":"2025-04-02T00:04:21.724546Z","shell.execute_reply":"2025-04-02T00:04:28.750247Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"![](https://i.imgur.com/TimBJX8.jpeg)Imgur","metadata":{}},{"cell_type":"markdown","source":"#### Very likely, that wasn't to match any image, however the moment I read ET, it was irresistable \n\n#### not to deliver this lines of code. Have fun and match the Challenge images.","metadata":{}}]}