{"cells":[{"metadata":{},"cell_type":"markdown","source":"**This notebook is to create a dataset of png train images based on the selected tiff level.**\n\nThe image processing consists of two steps:\n1. Cropping white background\n\nI used the method suggested by [Konstantin Lopuhin](https://www.kaggle.com/lopuhin)\nin his dataset [PANDA: Level 1 and 2 images](https://www.kaggle.com/lopuhin/panda-2020-level-1-2)\n\n2. Resizing to square without distortion\n\nI utilized the function by [Dieter](https://www.kaggle.com/christofhenkel) from his notebook [blend pd v8 kaz subv3 1:1](https://www.kaggle.com/christofhenkel/extract-image-features-from-pretrained-nn)","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Through these constants:\n\n* TIFF_LEVEL = 1\n* IMG_SIZE = 224\n\nthe code is set to produce 224 x 224 PNG from the second level images of train pyramidal TIFF, each of which has 3 levels.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport cv2\nfrom pathlib import Path\nfrom skimage.io import MultiImage\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom multiprocessing import Pool\nfrom tqdm.notebook import tqdm\n\ndef crop_white(image: np.ndarray, value: int = 255) -> np.ndarray:\n    assert image.shape[2] == 3\n    assert image.dtype == np.uint8\n    ys, = (image.min((1, 2)) < value).nonzero()\n    xs, = (image.min((0, 2)) < value).nonzero()\n    \n    # if there's no pixel with such a value\n    if len(xs) == 0 or len(ys) == 0:\n        return image\n    \n    return image[ys.min():ys.max() + 1, xs.min():xs.max() + 1]\n\ndef resize_to_square(image: np.ndarray, img_size: int = 224, color: list = [255, 255, 255]) -> np.ndarray:\n    old_size = image.shape[:2] # old_size is in (height, width) format\n    ratio = float(img_size)/max(old_size)\n    new_size = tuple([int(x*ratio) for x in old_size])\n    # new_size should be in (width, height) format\n    image = cv2.resize(image, (new_size[1], new_size[0]))\n    delta_w = img_size - new_size[1]\n    delta_h = img_size - new_size[0]\n    top, bottom = delta_h//2, delta_h-(delta_h//2)\n    left, right = delta_w//2, delta_w-(delta_w//2)\n    new_image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)\n    return new_image\n\ndef process_tiff(tiff_path: Path) -> bool:\n    multi_image = MultiImage(str(tiff_path))\n    assert cv2.imwrite(\n        str(SAVE_PATH.joinpath(tiff_path.with_suffix('.png').name)),\n        cv2.cvtColor(resize_to_square(crop_white(multi_image[TIFF_LEVEL], PIXEL_VALUE), IMG_SIZE, [PIXEL_VALUE, PIXEL_VALUE, PIXEL_VALUE]), cv2.COLOR_RGB2BGR)\n    )\n\nTIFF_LEVEL = 1\nIMG_SIZE = 224\nPIXEL_VALUE = 255\nTRAIN_IMAGES_PATH = Path(\"../input/prostate-cancer-grade-assessment/train_images/\")\nSAVE_PATH = Path(\"train_images\")\n\nSAVE_PATH.mkdir(exist_ok=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's visualize the image processing.","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"img = MultiImage('../input/prostate-cancer-grade-assessment/train_images/00412139e6b04d1e1cee8421f38f6e90.tiff')\n\nfig, ax = plt.subplots(1, 3, figsize=(16, 8))\n\nax[0].imshow(img[TIFF_LEVEL])\nax[0].set_title(f'Original, shape={img[TIFF_LEVEL].shape}')\n\nimg_cropped = crop_white(img[TIFF_LEVEL], PIXEL_VALUE) \nax[1].imshow(img_cropped)\nax[1].set_title(f'Cropped, shape={img_cropped.shape}')\n\nimg_resized = resize_to_square(img_cropped, IMG_SIZE, [PIXEL_VALUE, PIXEL_VALUE, PIXEL_VALUE]) \nax[2].imshow(img_resized)\nax[2].set_title(f'Resized, shape={img_resized.shape}')\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's parallelize the image processing on all the available CPUs to make it faster.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\n\nprint(f'{os.cpu_count()} CPU available')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images = list(TRAIN_IMAGES_PATH.glob('*.tiff'))\n\nwith Pool() as p:\n    with tqdm(total=len(train_images)) as pbar:\n        for r in p.imap_unordered(process_tiff, train_images):\n            pbar.update()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!zip -r -q train_images.zip train_images","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}