{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":37333,"databundleVersionId":3949526,"sourceType":"competition"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip -q install openslide-python","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:40:09.684046Z","iopub.execute_input":"2024-10-23T02:40:09.684407Z","iopub.status.idle":"2024-10-23T02:40:24.259085Z","shell.execute_reply.started":"2024-10-23T02:40:09.684373Z","shell.execute_reply":"2024-10-23T02:40:24.257889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Import Necessary Libraries**","metadata":{}},{"cell_type":"code","source":"import os \nimport sys\nimport numpy as np \nimport matplotlib.pyplot as plt \nfrom PIL import Image\nimport tifffile as tiff\nimport pandas as pd\nimport gc\nimport math\nimport cv2\nimport seaborn as sns\nimport openslide\nfrom openslide import open_slide\nfrom openslide.deepzoom import DeepZoomGenerator","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-23T02:40:24.261746Z","iopub.execute_input":"2024-10-23T02:40:24.262555Z","iopub.status.idle":"2024-10-23T02:40:26.329053Z","shell.execute_reply.started":"2024-10-23T02:40:24.262507Z","shell.execute_reply":"2024-10-23T02:40:26.32828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Read Data from CSV file**","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv('../input/mayo-clinic-strip-ai/train.csv')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:40:26.330301Z","iopub.execute_input":"2024-10-23T02:40:26.330778Z","iopub.status.idle":"2024-10-23T02:40:26.391487Z","shell.execute_reply.started":"2024-10-23T02:40:26.330742Z","shell.execute_reply":"2024-10-23T02:40:26.390593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Functions for Getting Threshold Value from Histogram**\n","metadata":{}},{"cell_type":"code","source":"def thresholding(img, method='otsu'):\n    # convert to grayscale complement image\n    grayscale_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n    img_c = 255 - grayscale_img\n    thres, thres_img = 0, img_c.copy()\n    if method == 'otsu':\n        thres, thres_img = cv2.threshold(img_c, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n    elif method == 'triangle':\n        thres, thres_img = cv2.threshold(img_c, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_TRIANGLE)\n    return thres, thres_img, img_c\n\ndef histogram(img, thres_img, img_c, thres):\n    \n    plt.figure(figsize=(15,15))\n    \n    plt.subplot(3,2,1)\n    plt.imshow(img)\n    plt.title('Scaled-down image')\n    \n    plt.subplot(3,2,2)\n    sns.histplot(img.ravel(), bins=np.arange(0,256), color='orange', alpha=0.5)\n    sns.histplot(img[:,:,0].ravel(), bins=np.arange(0,256), color='red', alpha=0.5)\n    sns.histplot(img[:,:,1].ravel(), bins=np.arange(0,256), color='Green', alpha=0.5)\n    sns.histplot(img[:,:,2].ravel(), bins=np.arange(0,256), color='Blue', alpha=0.5)\n    plt.legend(['Total', 'Red_Channel', 'Green_Channel', 'Blue_Channel'])\n    plt.ylim(0,0.05e6)\n    plt.xlabel('Intensity value')\n    plt.title('Color histogram')\n    \n    plt.subplot(3,2,3)\n    plt.imshow(img_c, cmap='gist_gray')\n    plt.title('Complement grayscale image')\n    \n    plt.subplot(3,2,4)\n    sns.histplot(img_c.ravel(), bins=np.arange(0,256))\n    plt.axvline(thres, c='red', linestyle=\"--\")\n    plt.ylim(0,0.05e6)\n    plt.xlabel('Intensity value')\n    plt.title('Grayscale complement histogram')\n    \n    plt.subplot(3,2,5)\n    plt.imshow(thres_img, cmap='gist_gray')\n    plt.title('Thresholded image')\n    \n    plt.subplot(3,2,6)\n    sns.histplot(thres_img.ravel(), bins=np.arange(0,256))\n    plt.axvline(thres, c='red', linestyle=\"--\")\n    plt.ylim(0,0.05e6)\n    plt.xlabel('Intensity value')\n    plt.title('Thresholded histogram')\n    \n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:40:26.394116Z","iopub.execute_input":"2024-10-23T02:40:26.394718Z","iopub.status.idle":"2024-10-23T02:40:26.409365Z","shell.execute_reply.started":"2024-10-23T02:40:26.394671Z","shell.execute_reply":"2024-10-23T02:40:26.408454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Functions for Visualizing and Rescaling Slide photos and Coverting to PNG**","metadata":{}},{"cell_type":"code","source":"def rescale_wsi(slide, scale_factor, save_path='/kaggle/working/'):\n    dims = slide.level_dimensions[0]  #the lowest resolution\n    large_w, large_h = slide.dimensions\n    new_w = math.floor(large_w / scale_factor)\n    new_h = math.floor(large_h / scale_factor)\n    wsi = slide.read_region((0, 0), 0, dims)  # read region at level 0\n    wsi = wsi.convert(\"RGB\")  # since img is in RGBA, need to convert to RGB for further preprocessing\n    rescale_img = wsi.resize((new_w, new_h), Image.Resampling.BILINEAR)  \n\n    if save_path:\n        \n        if os.path.isdir(save_path):        \n            png_name = os.path.join(save_path, \"rescaled_slide.png\")\n        else:\n            base_name, ext = os.path.splitext(save_path)\n            if ext.lower() != \".png\":\n                png_name = base_name + \".png\"\n            else:\n                png_name = save_path\n        rescale_img.save(png_name)\n    return rescale_img\ndef visualize_slide(df, loc, img):\n    plt.figure(figsize=(30,10))\n    plt.imshow(img)\n    plt.show()\n\ndef create_property_df(slide):\n    slide_properties = slide.properties\n    descriptions = ['The number of levels in the slide. Levels are numbered from 0 (highest resolution) to level_count - 1 (lowest resolution)',\n                    'A list of downsample factors for each level of the slide. level_downsamples[k] is the downsample factor of level k',\n                    'Height at level k',\n                    'Tile height at level k',\n                    'Tile width at level k',\n                    'Width at level k',\n                    'The name of the property containing an identification of the vendor',\n                    'Resolution Unit of the slide',\n                    'X Resolution',\n                    'Y Resolution',\n                    'A (width, height) tuple for level 0 of the slide',\n                    'Image mode/attribute'\n                   ]\n    properties = {}\n    smaller_region = slide.read_region((slide.dimensions[0]//2,slide.dimensions[1]//2), 0, (1024,1024))\n    for key, value in slide_properties.items():\n        properties[key] = value\n    properties['slide-dimension'] = slide.dimensions # width and height\n    properties['image-mode'] = smaller_region.mode\n    df_properties = pd.DataFrame.from_dict(properties, orient='index').reset_index() #create the df using dict keys as rows\n    df_properties.columns = ['Slide Property', 'Value']\n    df_properties['Description'] = descriptions\n    df_properties = df_properties[['Slide Property','Description','Value']]\n    return df_properties\n\ndef highlight(row):\n    df = lambda x: ['background: #8DE7E3' if x.name in row\n                        else '' for i in x]\n    return df","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:40:26.410846Z","iopub.execute_input":"2024-10-23T02:40:26.41123Z","iopub.status.idle":"2024-10-23T02:40:26.424774Z","shell.execute_reply.started":"2024-10-23T02:40:26.411188Z","shell.execute_reply":"2024-10-23T02:40:26.423928Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Creating Slides**","metadata":{}},{"cell_type":"code","source":"#Load the slide file \nslide = open_slide(\"../input/mayo-clinic-strip-ai/train/00c058_0.tif\")\nrescale_img = rescale_wsi(slide, 32)\ndf = create_property_df(slide)\ndf.style.hide().apply(highlight([0,2,5,7,11]), axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:40:26.425849Z","iopub.execute_input":"2024-10-23T02:40:26.426162Z","iopub.status.idle":"2024-10-23T02:42:56.862972Z","shell.execute_reply.started":"2024-10-23T02:40:26.426117Z","shell.execute_reply":"2024-10-23T02:42:56.861358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Visualize Slides**","metadata":{}},{"cell_type":"code","source":"visualize_slide(df, 3, rescale_img)","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:42:56.864387Z","iopub.execute_input":"2024-10-23T02:42:56.864809Z","iopub.status.idle":"2024-10-23T02:42:57.298886Z","shell.execute_reply.started":"2024-10-23T02:42:56.864765Z","shell.execute_reply":"2024-10-23T02:42:57.297872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Functions for creating Tiles**","metadata":{}},{"cell_type":"code","source":"def tile_properties(tiles):\n    tile_properties = {'Level count': ['The number of Deep Zoom levels in the image',tiles.level_count], \n            'Tile count': ['The total number of Deep Zoom tiles in the image',tiles.tile_count],\n            'Level tiles': ['A list of (tiles_x, tiles_y) tuples for each Deep Zoom level. level_tiles[k] are the tile counts of level k',tiles.level_tiles],\n            'Level dimensions': ['A list of (pixels_x, pixels_y) tuples for each Deep Zoom level. level_dimensions[k] are the dimensions of level k',tiles.level_dimensions]\n           }\n    tile_df = pd.DataFrame.from_dict(tile_properties, orient='index').reset_index()\n    tile_df.columns = ['Tile property', 'Description', 'Value']\n    return tile_df\n\ndef visualize_tiles(tiles, level, thres, tile_size):\n    rows, cols = tiles.level_tiles[level]\n    plt.figure(figsize=(10,10))\n    count = 0\n    img_size = 0\n    for row in range(rows):\n        for col in range(cols):\n            count += 1\n            plt.subplot(4,4,count)\n            plt.xticks([])\n            plt.yticks([])\n            single_tile = tiles.get_tile(level, (row,col))\n            single_tile_RGB = single_tile.convert('RGB')\n            img_test = np.array(single_tile_RGB.resize((tile_size, tile_size), Image.Resampling.BILINEAR))\n            img_size = img_test.shape\n            plt.imshow(img_test)\n            plt.tight_layout()\n    plt.suptitle(f'Tile level: {level}\\nNum tiles: {count}\\nTile size: {img_size}')\n    plt.tight_layout()\n    plt.show()\n    \n    plt.figure(figsize=(10,10))\n    count = 0\n    selected_tiles = 0\n    img_size = 0\n    for row in range(rows):\n        for col in range(cols):\n            count += 1\n            plt.subplot(4,4,count)\n            plt.xticks([])\n            plt.yticks([])\n            single_tile = tiles.get_tile(level, (row,col))\n            single_tile_RGB = single_tile.convert('RGB')\n            img_test = np.array(single_tile_RGB.resize((tile_size, tile_size), Image.Resampling.BILINEAR))\n            img_size = img_test.shape\n            img_c = 255 - img_test\n            if img_c.mean() > thres:\n                selected_tiles += 1\n                plt.imshow(img_test)\n                plt.tight_layout()\n    plt.suptitle(f'Tile level: {level}\\nNum selected tiles: {selected_tiles}\\nTile size: {img_size}')\n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:42:57.300248Z","iopub.execute_input":"2024-10-23T02:42:57.300887Z","iopub.status.idle":"2024-10-23T02:42:57.319568Z","shell.execute_reply.started":"2024-10-23T02:42:57.300837Z","shell.execute_reply":"2024-10-23T02:42:57.318472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Creating Tiles**","metadata":{}},{"cell_type":"code","source":"tiles = DeepZoomGenerator(slide, tile_size=1440, overlap=0, limit_bounds=True)\ntile_df = tile_properties(tiles)\ntile_df.style.hide().apply(highlight([1,3]), axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:42:57.320758Z","iopub.execute_input":"2024-10-23T02:42:57.321697Z","iopub.status.idle":"2024-10-23T02:42:57.34573Z","shell.execute_reply.started":"2024-10-23T02:42:57.321664Z","shell.execute_reply":"2024-10-23T02:42:57.344756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Visualizing Threshold from Histogram**","metadata":{}},{"cell_type":"code","source":"img_np = np.array(rescale_wsi(slide, 16))\nthres_triangle, thres_img, img_c = thresholding(img_np, method='triangle')\nhistogram(img_np, thres_img, img_c, thres_triangle)","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:42:57.348487Z","iopub.execute_input":"2024-10-23T02:42:57.348769Z","iopub.status.idle":"2024-10-23T02:45:23.676458Z","shell.execute_reply.started":"2024-10-23T02:42:57.348737Z","shell.execute_reply":"2024-10-23T02:45:23.675445Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Visualize Tiles**","metadata":{}},{"cell_type":"code","source":"visualize_tiles(tiles, 13, thres_triangle, 1440)","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:45:23.677492Z","iopub.execute_input":"2024-10-23T02:45:23.677757Z","iopub.status.idle":"2024-10-23T02:49:14.001768Z","shell.execute_reply.started":"2024-10-23T02:45:23.677727Z","shell.execute_reply":"2024-10-23T02:49:14.000872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Function for Visualizing Only Detected Pink Tiles**","metadata":{}},{"cell_type":"code","source":"def visualize_and_save_detected_pink_tiles(tiles, level, pink_threshold=0.1, output_path=\"detected_pink_tiles_visualization.png\", tile_size=(224, 224)):\n   \n    rows, cols = tiles.level_tiles[level]\n    detected_pink_tiles = []\n\n    # Iterate through each tile and check for pink content\n    for row in range(rows):\n        for col in range(cols):\n            single_tile = tiles.get_tile(level, (row, col))\n            single_tile_RGB = single_tile.convert('RGB')\n            tile_array = np.array(single_tile_RGB)\n\n            #Convert the tile to HSV for better detection of pink color\n            hsv_tile = cv2.cvtColor(tile_array, cv2.COLOR_RGB2HSV)\n\n            #Define the pink color range in HSV\n            lower_pink = np.array([140, 30, 100])  # Adjusted for better matching\n            upper_pink = np.array([180, 255, 255])\n\n            #Create a mask for pixels within the pink range\n            mask = cv2.inRange(hsv_tile, lower_pink, upper_pink)\n\n            #Calculate the ratio of pink pixels in the tile\n            pink_ratio = np.sum(mask > 0) / (tile_array.shape[0] * tile_array.shape[1])\n\n            #If pink ratio is above the threshold, add the tile to detected pink tiles list\n            if pink_ratio > pink_threshold:\n                detected_pink_tiles.append(tile_array)\n\n    #Visualize the detected pink tiles\n    num_tiles = len(detected_pink_tiles)\n    if num_tiles == 0:\n        print(\"No pink tiles detected for visualization.\")\n        return\n\n    #Plot detected pink tiles\n    plt.figure(figsize=(10, 10))\n    grid_size = int(np.ceil(np.sqrt(num_tiles)))  #fit all tiles\n\n    for i, tile in enumerate(detected_pink_tiles):\n        plt.subplot(grid_size, grid_size, i + 1)\n        plt.xticks([])\n        plt.yticks([])\n        tile_image = Image.fromarray(tile).resize(tile_size, Image.Resampling.BILINEAR)\n        plt.imshow(tile_image)\n\n    plt.suptitle(f'Num detected pink tiles: {num_tiles}')\n    plt.tight_layout()\n    plt.savefig(output_path, format='png')\n    plt.show()\n\n","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:49:14.00313Z","iopub.execute_input":"2024-10-23T02:49:14.003513Z","iopub.status.idle":"2024-10-23T02:49:14.016762Z","shell.execute_reply.started":"2024-10-23T02:49:14.003469Z","shell.execute_reply":"2024-10-23T02:49:14.015824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Visualize only Pink Tiles**","metadata":{}},{"cell_type":"code","source":"visualize_and_save_detected_pink_tiles(tiles, level=13, pink_threshold=0.1, output_path=\"/kaggle/working/detected_pink_tiles_visualization.png\")\n","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:49:14.017826Z","iopub.execute_input":"2024-10-23T02:49:14.018112Z","iopub.status.idle":"2024-10-23T02:51:06.180447Z","shell.execute_reply.started":"2024-10-23T02:49:14.018081Z","shell.execute_reply":"2024-10-23T02:51:06.179582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Use Pre-trained Model for Feature Extraction**","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\nfrom tensorflow.keras.preprocessing.image import img_to_array\nimport numpy as np\nfrom PIL import Image\n\n#Pre-trained Model\nvgg_model = VGG16(weights='imagenet', include_top=False)\n\n#List to store the extracted features for each filtered pink tile\npink_tile_features = []\n\n#Level at tiles are extracted\nlevel = 13\nrows, cols = tiles.level_tiles[level]\n\n\nfor row in range(rows):\n    for col in range(cols):\n        # Get the tile using get_tile method\n        single_tile = tiles.get_tile(level, (row, col))\n        single_tile_RGB = single_tile.convert('RGB')\n        tile_array = np.array(single_tile_RGB)\n\n        #Convert tile to PIL image, resize it to 224x224, and convert to array\n        tile_image = Image.fromarray(tile_array).resize((224, 224))\n        tile_array = img_to_array(tile_image)\n\n        #Expand dimensions to match VGG16 input shape and preprocess the image\n        tile_array = np.expand_dims(tile_array, axis=0)\n        tile_array = preprocess_input(tile_array)\n\n        #Extract features\n        features = vgg_model.predict(tile_array)\n        \n\n        #Flatten the features\n        pink_tile_features.append(features.flatten())\n","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:51:06.18179Z","iopub.execute_input":"2024-10-23T02:51:06.182178Z","iopub.status.idle":"2024-10-23T02:53:24.123782Z","shell.execute_reply.started":"2024-10-23T02:51:06.182124Z","shell.execute_reply":"2024-10-23T02:53:24.12296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **TNSE visualization**","metadata":{}},{"cell_type":"code","source":"from sklearn.manifold import TSNE\nfrom mpl_toolkits.mplot3d import Axes3D\n\nif len(pink_tile_features) == 0:\n    print(\"No filtered pink tiles available for feature extraction.\")\nelse:\n    #Covert to array\n    feature_array = np.array(pink_tile_features)\n\n    #t-SNE \n    tsne = TSNE(n_components=3, random_state=42, perplexity=min(5, len(pink_tile_features) - 1))\n    reduced_features = tsne.fit_transform(feature_array)\n\n    # 3D representation of the features\n    fig = plt.figure(figsize=(10, 8))\n    ax = fig.add_subplot(111, projection='3d')\n    ax.scatter(reduced_features[:, 0], reduced_features[:, 1], reduced_features[:, 2], c='red', label='Extracted Features')\n    ax.set_title('t-SNE Visualization of Extracted Features in 3D')\n    ax.set_xlabel('Dimension 1')\n    ax.set_ylabel('Dimension 2')\n    ax.set_zlabel('Dimension 3')\n    ax.legend()\n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-23T02:53:24.124957Z","iopub.execute_input":"2024-10-23T02:53:24.12555Z","iopub.status.idle":"2024-10-23T02:53:26.09933Z","shell.execute_reply.started":"2024-10-23T02:53:24.125515Z","shell.execute_reply":"2024-10-23T02:53:26.098405Z"},"trusted":true},"execution_count":null,"outputs":[]}]}