{"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":"Find further information in [this post](https://www.kaggle.com/competitions/uw-madison-gi-tract-image-segmentation/discussion/337313)\n\nKey points to do intelligent cropping:\n* median filter with zero padding to reduce noise\n* crop all slices in a sequence at the same indices\n* keep aspect ratio (this can be skipped)","metadata":{}},{"cell_type":"markdown","source":"# Load sample sequence of images","metadata":{}},{"cell_type":"code","source":"from pathlib import Path\nimport numpy as np\nimport cv2\nimport matplotlib.pyplot as plt\n\npath = Path(f'../input/uw-madison-gi-tract-image-segmentation/train/case134/case134_day21/scans/')\n\nimages = []\ncount = 0\nfor filename in sorted(path.rglob('*.png')):\n    image = cv2.imread(str(filename), -1)\n    image = np.array(image, dtype=int)\n    images.append(image)\n    count += 1\n    if count == 144:\n        break","metadata":{"execution":{"iopub.status.busy":"2022-07-15T11:17:31.494279Z","iopub.execute_input":"2022-07-15T11:17:31.495055Z","iopub.status.idle":"2022-07-15T11:17:32.039727Z","shell.execute_reply.started":"2022-07-15T11:17:31.495016Z","shell.execute_reply":"2022-07-15T11:17:32.038570Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Normalize\n\nWe decided to normalize using percentile and not maximum, since some slices contained noise. This boosted ~0.001 our score vs normalizing with maximum","metadata":{}},{"cell_type":"code","source":"images = [img.astype(np.float32) / np.percentile(img, 99) for img in images]","metadata":{"execution":{"iopub.status.busy":"2022-07-15T11:17:32.041898Z","iopub.execute_input":"2022-07-15T11:17:32.042747Z","iopub.status.idle":"2022-07-15T11:17:32.221762Z","shell.execute_reply.started":"2022-07-15T11:17:32.042708Z","shell.execute_reply":"2022-07-15T11:17:32.220641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Function to crop","metadata":{}},{"cell_type":"code","source":"from scipy.ndimage import median_filter\n\ndef crop_slices(slices, tol=0.05, apply_median=True, keep_aspect_ratio=False):\n    row_start_general = 10000\n    col_start_general = 10000\n    row_end_general = 0\n    col_end_general = 0\n\n    for slice_ in slices:\n        if apply_median:\n            # Apply median filter to remove noise\n            slice_ = median_filter(slice_, size=15, mode='constant', cval=0)\n        \n        slice_mask = slice_ > tol\n        m,n = slice_mask.shape\n        mask0,mask1 = slice_mask.any(0),slice_mask.any(1)\n        col_start,col_end = mask0.argmax(),n-mask0[::-1].argmax()\n        row_start,row_end = mask1.argmax(),m-mask1[::-1].argmax()\n\n        row_start_general = min(row_start_general, row_start)\n        col_start_general = min(col_start_general, col_start)\n        row_end_general = max(row_end_general, row_end)\n        col_end_general = max(col_end_general, col_end)\n        \n    add_col, add_row = 0, 0\n    \n    if keep_aspect_ratio:\n\n        original_aspect_ratio = slice_.shape[0] / slice_.shape[1]\n        new_aspect_ratio = (row_end_general - row_start_general) / (col_end_general - col_start_general)\n\n        if (new_aspect_ratio - original_aspect_ratio) > 1e-2:  # TODO: define better tolerance\n            # Increase denominator\n            objective_denominator = (row_end_general - row_start_general) / original_aspect_ratio\n            add_col = int((objective_denominator - (col_end_general - col_start_general)) / 2)\n            assert add_col >= 0\n\n        elif (original_aspect_ratio - new_aspect_ratio) > 1e-2:\n            # Increase numerator\n            objective_numerator = (col_end_general - col_start_general) * original_aspect_ratio\n            add_row = int((objective_numerator - (row_end_general - row_start_general)) / 2)\n            assert add_row >= 0\n\n    slices_cropped = slices[:, row_start_general:row_end_general, col_start_general:col_end_general]\n    \n    return np.pad(slices_cropped, ((0, 0), (add_row, add_row), (add_col, add_col)), constant_values=0)","metadata":{"execution":{"iopub.status.busy":"2022-07-15T11:20:04.730544Z","iopub.execute_input":"2022-07-15T11:20:04.730940Z","iopub.status.idle":"2022-07-15T11:20:04.745592Z","shell.execute_reply.started":"2022-07-15T11:20:04.730908Z","shell.execute_reply":"2022-07-15T11:20:04.744330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Check results","metadata":{}},{"cell_type":"markdown","source":"## Original image","metadata":{}},{"cell_type":"code","source":"plt.imshow(images[70], cmap='gray')\nplt.axis('off')","metadata":{"execution":{"iopub.status.busy":"2022-07-15T11:20:05.892580Z","iopub.execute_input":"2022-07-15T11:20:05.893341Z","iopub.status.idle":"2022-07-15T11:20:05.985312Z","shell.execute_reply.started":"2022-07-15T11:20:05.893301Z","shell.execute_reply":"2022-07-15T11:20:05.984089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Crop without median","metadata":{}},{"cell_type":"code","source":"images_cropped = crop_slices(np.array(images[65:75]), apply_median=False)\nplt.imshow(images_cropped[5], cmap='gray')\nplt.axis('off')","metadata":{"execution":{"iopub.status.busy":"2022-07-15T11:20:06.696521Z","iopub.execute_input":"2022-07-15T11:20:06.696919Z","iopub.status.idle":"2022-07-15T11:20:06.999036Z","shell.execute_reply.started":"2022-07-15T11:20:06.696888Z","shell.execute_reply":"2022-07-15T11:20:06.997779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Crop with median","metadata":{}},{"cell_type":"code","source":"images_cropped = crop_slices(np.array(images[65:75]), apply_median=True)\nplt.imshow(images_cropped[5], cmap='gray')\nplt.axis('off')","metadata":{"execution":{"iopub.status.busy":"2022-07-15T11:20:09.548282Z","iopub.execute_input":"2022-07-15T11:20:09.548708Z","iopub.status.idle":"2022-07-15T11:20:12.163697Z","shell.execute_reply.started":"2022-07-15T11:20:09.548674Z","shell.execute_reply":"2022-07-15T11:20:12.162414Z"},"trusted":true},"execution_count":null,"outputs":[]}]}