{"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":45867,"databundleVersionId":6924515,"sourceType":"competition"},{"sourceId":6774400,"sourceType":"datasetVersion","datasetId":3895136},{"sourceId":147716186,"sourceType":"kernelVersion"}],"dockerImageVersionId":30558,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!ls /kaggle/input/pyvips-python-and-deb-package\n# intall the deb packages\n!dpkg -i --force-depends /kaggle/input/pyvips-python-and-deb-package/linux_packages/archives/*.deb\n# install the python wrapper\n!pip install pyvips -f /kaggle/input/pyvips-python-and-deb-package/python_packages/ --no-index","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-11-18T20:43:12.820191Z","iopub.execute_input":"2023-11-18T20:43:12.820609Z","iopub.status.idle":"2023-11-18T20:44:16.26396Z","shell.execute_reply.started":"2023-11-18T20:43:12.820583Z","shell.execute_reply":"2023-11-18T20:44:16.263095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Decompose image to tiles/grid 🖽","metadata":{}},{"cell_type":"code","source":"import os\nimport pyvips\nimport numpy as np\nfrom PIL import Image\n\nos.environ['VIPS_DISC_THRESHOLD'] = '9gb'\n\ndef extract_image_tiles(\n    p_img, folder, size: int = 768, scale: float = 1.0, drop_thr: float = 0.8\n) -> list:\n    name, _ = os.path.splitext(os.path.basename(p_img))\n    im = pyvips.Image.new_from_file(p_img)\n    w = h = size\n    # https://stackoverflow.com/a/47581978/4521646\n    inds = [(y, y + h, x, x + w)\n            for y in range(0, im.height, h) for x in range(0, im.width, w)]\n    files, idxs = [], []\n    for k, idx in enumerate(inds):\n        y, y_, x, x_ = idx\n        # https://libvips.github.io/pyvips/vimage.html#pyvips.Image.crop\n        tile = im.crop(x, y, min(w, im.width - x), min(h, im.height - y)).numpy()[..., :3]\n        if tile.shape[:2] != (h, w):\n            tile_ = tile\n            tile_size = (h, w) if tile.ndim == 2 else (h, w, tile.shape[2])\n            tile = np.zeros(tile_size, dtype=tile.dtype)\n            tile[:tile_.shape[0], :tile_.shape[1], ...] = tile_\n        mask_bg = np.sum(tile, axis=2) == 0\n        if np.sum(mask_bg) >= (np.prod(mask_bg.shape) * drop_thr):\n            #print(f\"skip almost empty tile: {k:06}_{int(x_ / w)}-{int(y_ / h)}\")\n            continue\n        tile[mask_bg, :] = 255\n        mask_bg = np.mean(tile, axis=2) > 240\n        if np.sum(mask_bg) >= (np.prod(mask_bg.shape) * drop_thr):\n            #print(f\"skip almost empty tile: {k:06}_{int(x_ / w)}-{int(y_ / h)}\")\n            continue\n        p_img = os.path.join(folder, f\"{k:06}_{int(x_ / w)}-{int(y_ / h)}.png\")\n        # print(tile.shape, tile.dtype, tile.min(), tile.max())\n        new_size = int(size * scale), int(size * scale)\n        Image.fromarray(tile).resize(new_size, Image.LANCZOS).save(p_img)\n        files.append(p_img)\n        idxs.append(idx)\n    return files, idxs","metadata":{"execution":{"iopub.status.busy":"2023-11-18T20:44:16.266442Z","iopub.execute_input":"2023-11-18T20:44:16.266787Z","iopub.status.idle":"2023-11-18T20:44:16.616203Z","shell.execute_reply.started":"2023-11-18T20:44:16.266759Z","shell.execute_reply":"2023-11-18T20:44:16.614897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATASET_IMAGES = \"/kaggle/input/UBC-OCEAN/train_images\"\n\n!mkdir -p /kaggle/temp/images\n!rm -f /kaggle/temp/images/*.png\n\ntiles_img, _ = extract_image_tiles(\n    os.path.join(DATASET_IMAGES, \"12244.png\"),\n    \"/kaggle/temp/images\", size=1024, scale=0.5\n)\n\n!ls -lh /kaggle/temp/images","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-11-18T20:44:16.618291Z","iopub.execute_input":"2023-11-18T20:44:16.618633Z","iopub.status.idle":"2023-11-18T20:45:25.275988Z","shell.execute_reply.started":"2023-11-18T20:44:16.618604Z","shell.execute_reply":"2023-11-18T20:45:25.274399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Show the image tiles with segmentations","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nnames = [os.path.splitext(os.path.basename(p_img))[0] for p_img in tiles_img]\npos = [name.split(\"_\")[-1] for name in names]\nidx_x, idx_y = zip(*[list(map(int, p.split(\"-\"))) for p in pos])\nnb_rows = len(set(idx_y))\nnb_cols = len(set(idx_x))\nprint(f\"{nb_rows=}\\n{nb_cols=}\")\n\nfig, axes = plt.subplots(nrows=nb_rows, ncols=nb_cols,\n    figsize=(nb_cols * 0.5, nb_rows * 0.5)\n)\nfor i in range(nb_rows):\n    for j in range(nb_cols):\n        axes[i, j].set_facecolor(\"aqua\")\n        axes[i, j].set_xticklabels([])\n        axes[i, j].set_yticklabels([])\n\nfor p_img, x, y in zip(tiles_img, idx_x, idx_y):\n    img = plt.imread(p_img)\n    ax = axes[y - 1, x - 1]\n    ax.imshow(img)\nprint(f\"image size: {img.shape}\")\n\nplt.subplots_adjust(wspace=0, hspace=0)\n# # fig.tight_layout()","metadata":{"execution":{"iopub.status.busy":"2023-11-18T20:45:25.278763Z","iopub.execute_input":"2023-11-18T20:45:25.279105Z","iopub.status.idle":"2023-11-18T20:46:10.359943Z","shell.execute_reply.started":"2023-11-18T20:45:25.279076Z","shell.execute_reply":"2023-11-18T20:46:10.35842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Export all image tiles¶","metadata":{}},{"cell_type":"code","source":"import random\n\ndef subsample_rand_prune(files: list, max_samples: float = 1.0):\n    max_samples = max_samples if isinstance(max_samples, int) else int(len(files) * max_samples)\n    random.shuffle(files)\n    for p_img in files[max_samples:]:\n        os.remove(p_img)","metadata":{"execution":{"iopub.status.busy":"2023-11-18T20:46:10.361575Z","iopub.execute_input":"2023-11-18T20:46:10.361904Z","iopub.status.idle":"2023-11-18T20:46:10.369345Z","shell.execute_reply.started":"2023-11-18T20:46:10.361876Z","shell.execute_reply":"2023-11-18T20:46:10.367691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc, time\n\ndef extract_prune_tiles(\n    idx_path_img: str, folder: str = \"./train_tiles\",\n    size: int = 1600, scale: float = 0.125,\n    drop_thr: float = 0.8, max_samples: float = 1.0\n) -> None:\n    idx, p_img = idx_path_img\n    print(f\"processing #{idx}: {p_img}\")\n    name, _ = os.path.splitext(os.path.basename(p_img))\n    folder = os.path.join(folder, name)\n    os.makedirs(folder, exist_ok=True)\n    tiles, _ = extract_image_tiles(p_img, folder, size, scale, drop_thr)\n    subsample_rand_prune(tiles, max_samples)\n    gc.collect()\n    time.sleep(1)","metadata":{"execution":{"iopub.status.busy":"2023-11-18T20:46:10.370422Z","iopub.execute_input":"2023-11-18T20:46:10.370754Z","iopub.status.idle":"2023-11-18T20:46:10.391219Z","shell.execute_reply.started":"2023-11-18T20:46:10.370725Z","shell.execute_reply":"2023-11-18T20:46:10.389632Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\nimport multiprocessing as mproc\nfrom tqdm.auto import tqdm\nfrom joblib import Parallel, delayed\n\n!mkdir -p train_tiles\n!rm -f /kaggle/temp/images/*.png\n\nls = glob.glob(os.path.join(DATASET_IMAGES, '*.png'))\nprint(f\"found images: {len(ls)}\")\n\n# for id_pimg in tqdm(enumerate(ls)):\n#     extract_prune_tiles(id_pimg, \"train_tiles, size=1024, scale=0.1, max_samples=0.7)\n\npool = mproc.Pool(3)\ntqdm_bar = tqdm(total=len(ls))\nfor _ in pool.imap_unordered(extract_prune_tiles, enumerate(ls)):\n    tqdm_bar.update()\npool.close()\npool.join()\n\n# _= Parallel(n_jobs=4)(\n#     delayed(extract_prune_tiles)\n#     (id_pimg, \"train_tiles\", size=1600, scale=0.15, drop_thr=0.8)\n#     for id_pimg in tqdm(enumerate(ls))\n# )","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-11-18T20:46:10.393331Z","iopub.execute_input":"2023-11-18T20:46:10.39386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Show some samples","metadata":{}},{"cell_type":"code","source":"ls = [p for p in glob.glob('train_tiles/*') if os.path.isdir(p)]\nprint(f\"found folders: {len(ls)}\")\nls = glob.glob('train_tiles/*/*.png')\nprint(f\"found images: {len(ls)}\")\n\nfig, axes = plt.subplots(nrows=5, ncols=5, figsize=(10, 10))\nfor i, p_img in enumerate(ls[:25]):\n    img = plt.imread(p_img)\n    ax = axes[i // 5, i % 5]\n    ax.imshow(img)\n    #ax.set_axis_off()","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}