{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Pixel coordinate generation","metadata":{}},{"cell_type":"markdown","source":"In this notebook, I have rewritten the process for getting pixels coordinates described in the [Tutorial notebook](https://www.kaggle.com/code/jpposma/vesuvius-challenge-ink-detection-tutorial) \n\nThe aim of it is to assist the process of dataset creation described in that notebook, and to rapidly speed it up.\n\nThe original way took ~70 seconds, my way speeds this up by eliminating the need for a loop, allowing it to run in less than 1 second. Over 100x faster :)\n\nAt the bottom of the notebook I verify both ways produce identical outputs so we can be sure it is working correctly.","metadata":{}},{"cell_type":"code","source":"import torch\nimport numpy as np\nimport PIL\nimport matplotlib.pyplot as plt\nimport matplotlib\nfrom pathlib import Path\nimport os\nimport time\n\ndevice = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(f\"on device: {device}\")\n\nBUFFER = 30 # ie. each square into network is 30*2+1=61 wide\nrect = (1100, 3500, 700, 950) # (x, y, w, h)","metadata":{"execution":{"iopub.status.busy":"2023-03-18T03:46:17.488623Z","iopub.execute_input":"2023-03-18T03:46:17.488998Z","iopub.status.idle":"2023-03-18T03:46:19.790273Z","shell.execute_reply.started":"2023-03-18T03:46:17.488962Z","shell.execute_reply":"2023-03-18T03:46:19.789143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"root_filepath = '/kaggle/input/vesuvius-challenge-ink-detection/train/1/'\n#['inklabels.png', 'inklabels_rle.csv', 'ir.png', 'mask.png', 'surface_volume']\ntif_filenames = sorted(os.listdir(root_filepath+'surface_volume'))\nprint(len(tif_filenames), tif_filenames[:5])\n\nmask = torch.from_numpy(np.array(PIL.Image.open(root_filepath+\"mask.png\").convert('1')))\nlabel = torch.from_numpy(np.array(PIL.Image.open(root_filepath+\"inklabels.png\"))).float().to(device)","metadata":{"execution":{"iopub.status.busy":"2023-03-18T03:46:19.792130Z","iopub.execute_input":"2023-03-18T03:46:19.792520Z","iopub.status.idle":"2023-03-18T03:46:20.264950Z","shell.execute_reply.started":"2023-03-18T03:46:19.792494Z","shell.execute_reply":"2023-03-18T03:46:20.264118Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots()\nax.imshow(label.cpu(), cmap = 'gray')\npatch1 = matplotlib.patches.Rectangle((rect[0], rect[1]), rect[2], rect[3], linewidth=1, edgecolor='r', facecolor='none')\nax.add_patch(patch1)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-18T03:46:20.266077Z","iopub.execute_input":"2023-03-18T03:46:20.266687Z","iopub.status.idle":"2023-03-18T03:46:21.661073Z","shell.execute_reply.started":"2023-03-18T03:46:20.266653Z","shell.execute_reply":"2023-03-18T03:46:21.659899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots()\nax.imshow(mask, cmap = 'gray')\npatch1 = matplotlib.patches.Rectangle((rect[0], rect[1]), rect[2], rect[3], linewidth=1, edgecolor='r', facecolor='none')\nax.add_patch(patch1)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-03-18T03:46:29.670601Z","iopub.execute_input":"2023-03-18T03:46:29.670975Z","iopub.status.idle":"2023-03-18T03:46:30.826140Z","shell.execute_reply.started":"2023-03-18T03:46:29.670942Z","shell.execute_reply":"2023-03-18T03:46:30.824519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The functions below produce all pixel coordinates for pixels within the rectangle and outside it. (Note: In both coordinates are restricted to the mask)","metadata":{}},{"cell_type":"code","source":"%%time\n# Takes in a mask, and outputs the set of pixels (x,y) in intersection of that mask with a rectangle\n# Also outputs the set intersection of that mask with the exterior of the rectangle\n\ndef get_pixels():\n    max_h,max_w = mask.shape # Height and width of mask\n    x, y, w, h = rect\n    \n    # Create a Boolean array of the same shape as the bitmask, initially all True\n    not_border = np.zeros(mask.shape, dtype=bool)\n    not_border[BUFFER:max_h-BUFFER, BUFFER:max_w-BUFFER] = True\n    arr_mask = np.array(mask) * not_border\n    \n    inside_rect = np.zeros(mask.shape, dtype=bool) * arr_mask\n    # Sets all indexes with inside_rect array to true\n    inside_rect[y:y+h+1, x:x+w+1] = True\n    \n    outside_rect = np.ones(mask.shape, dtype=bool) * arr_mask\n    # Set the pixels within the inside_rect to False\n    outside_rect[y:y+h+1, x:x+w+1] = False\n    \n    return np.argwhere(inside_rect), np.argwhere(outside_rect)\n    \npixels_inside_rect2, pixels_outside_rect2 = get_pixels()","metadata":{"execution":{"iopub.status.busy":"2023-03-18T02:24:30.204392Z","iopub.execute_input":"2023-03-18T02:24:30.204837Z","iopub.status.idle":"2023-03-18T02:24:31.123421Z","shell.execute_reply.started":"2023-03-18T02:24:30.204771Z","shell.execute_reply":"2023-03-18T02:24:31.122175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nprint(\"Generating pixel lists...\")\n# Split our dataset into train and val. The pixels inside the rect are the \n# val set, and the pixels outside the rect are the train set.\npixels_inside_rect = []\npixels_outside_rect = []\nfor pixel in zip(*np.where(mask == 1)):\n    if pixel[1] < BUFFER or pixel[1] >= mask.shape[1]-BUFFER or pixel[0] < BUFFER or pixel[0] >= mask.shape[0]-BUFFER:\n        continue # Too close to the edge\n    if pixel[1] >= rect[0] and pixel[1] <= rect[0]+rect[2] and pixel[0] >= rect[1] and pixel[0] <= rect[1]+rect[3]:\n        pixels_inside_rect.append(pixel)\n    else:\n        pixels_outside_rect.append(pixel)\n\nprint(f\"pixels_inside_rect: {len(pixels_inside_rect)} | pixels_outside_rect: {len(pixels_outside_rect)}\")","metadata":{"execution":{"iopub.status.busy":"2023-03-18T02:24:44.539343Z","iopub.execute_input":"2023-03-18T02:24:44.539762Z","iopub.status.idle":"2023-03-18T02:25:52.860704Z","shell.execute_reply.started":"2023-03-18T02:24:44.539726Z","shell.execute_reply":"2023-03-18T02:25:52.859391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pixels_inside_rect2, np.array(pixels_inside_rect)","metadata":{"execution":{"iopub.status.busy":"2023-03-18T02:25:52.863138Z","iopub.execute_input":"2023-03-18T02:25:52.864131Z","iopub.status.idle":"2023-03-18T02:25:53.244379Z","shell.execute_reply.started":"2023-03-18T02:25:52.864088Z","shell.execute_reply":"2023-03-18T02:25:53.242916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Pixel coordinates match up perfectly :)\n\nprint((np.array(pixels_inside_rect) == pixels_inside_rect2).min())\nprint((np.array(pixels_outside_rect) == pixels_outside_rect2).min())","metadata":{"execution":{"iopub.status.busy":"2023-03-18T02:25:53.246128Z","iopub.execute_input":"2023-03-18T02:25:53.247516Z","iopub.status.idle":"2023-03-18T02:26:10.172059Z","shell.execute_reply.started":"2023-03-18T02:25:53.247455Z","shell.execute_reply":"2023-03-18T02:26:10.170641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}