{"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":"none","dataSources":[{"sourceId":45867,"databundleVersionId":6924515,"sourceType":"competition"},{"sourceId":7328643,"sourceType":"datasetVersion","datasetId":3896252},{"sourceId":202584656,"sourceType":"kernelVersion"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:35:10.670664Z","iopub.execute_input":"2024-11-14T12:35:10.671221Z","iopub.status.idle":"2024-11-14T12:35:10.903086Z","shell.execute_reply.started":"2024-11-14T12:35:10.671158Z","shell.execute_reply":"2024-11-14T12:35:10.901709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!yes | sudo dpkg -i /kaggle/input/project-1-lib/libvips/*.deb\n!pip install /kaggle/input/project-1-lib/pyvips/pyvips-2.2.3-py2.py3-none-any.whl --no-index --find-links /kaggle/input/libvips-pyvips-installation-and-getting-started/pyvips\n!pip install /kaggle/input/ubc-ocean-dataset/packages/imagesize-1.4.1-py2.py3-none-any.whl","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:35:38.642485Z","iopub.execute_input":"2024-11-14T12:35:38.642996Z","iopub.status.idle":"2024-11-14T12:36:49.492856Z","shell.execute_reply.started":"2024-11-14T12:35:38.642949Z","shell.execute_reply":"2024-11-14T12:36:49.491337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"pip install -U albumentations","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:37:00.651246Z","iopub.execute_input":"2024-11-14T12:37:00.652357Z","iopub.status.idle":"2024-11-14T12:37:14.936627Z","shell.execute_reply.started":"2024-11-14T12:37:00.652295Z","shell.execute_reply":"2024-11-14T12:37:14.934992Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport yaml\nfrom pathlib import Path\nfrom tqdm import tqdm\nimport numpy as np\nimport pandas as pd\n\nos.environ['OPENCV_IO_MAX_IMAGE_PIXELS'] = str(pow(2, 40))\nimport cv2\nimport pyvips\nimport imagesize\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport timm\n\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\n\nimport matplotlib.pyplot as plt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:37:25.991104Z","iopub.execute_input":"2024-11-14T12:37:25.991616Z","iopub.status.idle":"2024-11-14T12:37:26.001487Z","shell.execute_reply.started":"2024-11-14T12:37:25.991564Z","shell.execute_reply":"2024-11-14T12:37:25.999943Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"competition_dataset = Path('/kaggle/input/UBC-OCEAN')\nexternal_dataset = Path('/kaggle/input/ubc-ocean-dataset')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:37:30.696048Z","iopub.execute_input":"2024-11-14T12:37:30.696504Z","iopub.status.idle":"2024-11-14T12:37:30.702317Z","shell.execute_reply.started":"2024-11-14T12:37:30.69646Z","shell.execute_reply":"2024-11-14T12:37:30.700917Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv(competition_dataset / 'test.csv')\nis_submission = df.shape[0] != 1\n\ndf['image_type'] = 'wsi'\ndf.loc[(df['image_width'] < 4000) & (df['image_height'] < 4000), 'image_type'] = 'tma'\ndf['image_path'] = df['image_id'].apply(lambda x: str(competition_dataset / 'test_images' / f'{str(x)}.png'))\n\nprint(f'Dataset Shape: {df.shape}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:37:34.334279Z","iopub.execute_input":"2024-11-14T12:37:34.33473Z","iopub.status.idle":"2024-11-14T12:37:34.353891Z","shell.execute_reply.started":"2024-11-14T12:37:34.334688Z","shell.execute_reply":"2024-11-14T12:37:34.352084Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def read_image(image_path):\n    \n    \"\"\"\n    Read image using libvips\n\n    Parameters\n    ----------\n    image_path: str\n        Path of the image\n\n    Returns\n    -------\n    image: numpy.ndarray of shape (height, width, 3)\n        Image array\n    \"\"\"\n    \n    image = pyvips.Image.new_from_file(image_path, access='sequential')\n\n    return np.ndarray(\n        buffer=image.write_to_memory(),\n        dtype=np.uint8,\n        shape=[image.height, image.width, image.bands]\n    )\ndef resize_with_aspect_ratio(image, longest_edge, interpolation=cv2.INTER_LINEAR):\n\n    \"\"\"\n    Resize image while preserving its aspect ratio\n\n    Parameters\n    ----------\n    image: numpy.ndarray of shape (height, width, 3)\n        Image array\n\n    longest_edge: int\n        Desired number of pixels on the longest edge\n\n    interpolation: int\n        OpenCV interpolation enum\n\n    Returns\n    -------\n    image: numpy.ndarray of shape (resized_height, resized_width, 3)\n        Resized image array\n    \"\"\"\n\n    height, width = image.shape[:2]\n    scale = longest_edge / max(height, width)\n    image = cv2.resize(image, dsize=(int(np.ceil(width * scale)), int(np.ceil(height * scale))), interpolation=interpolation)\n\n    return image\ndef drop_low_std(image, threshold):\n\n    \"\"\"\n    Drop rows and columns that are below the given standard deviation threshold\n\n    Parameters\n    ----------\n    image: numpy.ndarray of shape (height, width, 3)\n        Image array\n\n    threshold: int\n        Standard deviation threshold\n\n    Returns\n    -------\n    image: numpy.ndarray of shape (cropped_height, cropped_width, 3)\n        Cropped image array\n    \"\"\"\n\n    vertical_stds = image.std(axis=(1, 2))\n    horizontal_stds = image.std(axis=(0, 2))\n    cropped_image = image[vertical_stds > threshold, :, :]\n    cropped_image = cropped_image[:, horizontal_stds > threshold, :]\n\n    return cropped_image\ndef get_largest_contour(image, threshold):\n\n    \"\"\"\n    Get the largest contour from the image\n\n    Parameters\n    ----------\n    image: numpy.ndarray of shape (height, width)\n        Image array\n\n    threshold: int\n        Binarization threshold\n\n    Returns\n    -------\n    bounding_box: list of shape (4)\n        Bounding box with x1, y1, x2, y2 values\n    \"\"\"\n    \n    image_shape = image.shape[:2]\n    image = cv2.threshold(image, threshold, 255, cv2.THRESH_BINARY)[1]\n    contours, _ = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)\n    del image\n    if len(contours) == 0:\n        x1 = 0\n        x2 = image_shape[1] + 1\n        y1 = 0\n        y2 = image_shape[0] + 1\n    else:\n        contour = max(contours, key=cv2.contourArea)\n        mask = np.zeros(image_shape, np.uint8)\n        cv2.drawContours(mask, [contour], -1, 255, cv2.FILLED)\n\n        y1, y2 = np.min(contour[:, :, 1]), np.max(contour[:, :, 1])\n        x1, x2 = np.min(contour[:, :, 0]), np.max(contour[:, :, 0])\n\n        x1 = int(0.999 * x1)\n        x2 = int(1.001 * x2)\n        y1 = int(0.999 * y1)\n        y2 = int(1.001 * y2)\n\n    bounding_box = [x1, y1, min(x2, image_shape[1]), min(y2, image_shape[0])]\n\n    return bounding_box","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:37:38.534052Z","iopub.execute_input":"2024-11-14T12:37:38.53451Z","iopub.status.idle":"2024-11-14T12:37:38.554539Z","shell.execute_reply.started":"2024-11-14T12:37:38.534469Z","shell.execute_reply":"2024-11-14T12:37:38.55303Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def visualize_image(image, title, mask=None, path=None):\n\n    \"\"\"\n    Visualize the given image\n\n    Parameters\n    ----------\n    image: numpy.ndarray of shape (height, width, channel)\n        Image array\n\n    title: str\n        Title of the plot\n\n    mask: numpy.ndarray of shape (height, width)\n        Mask array\n\n    path: str or None\n        Path of the output file or None (if path is None, plot is displayed with selected backend)\n    \"\"\"\n    fig, ax = plt.subplots(figsize=(8, 8))\n    ax.imshow(image)\n    if mask is not None:\n        ax.imshow(mask, alpha=0.5)\n    ax.set_xlabel('')\n    ax.set_ylabel('')\n    ax.tick_params(axis='x', labelsize=15, pad=10)\n    ax.tick_params(axis='y', labelsize=15, pad=10)\n    ax.set_title(title, size=15, pad=12.5, loc='center', wrap=True)\n\n    if path is None:\n        plt.show()\n    else:\n        plt.savefig(path)\n        plt.close(fig)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:37:45.62332Z","iopub.execute_input":"2024-11-14T12:37:45.623768Z","iopub.status.idle":"2024-11-14T12:37:45.634394Z","shell.execute_reply.started":"2024-11-14T12:37:45.623724Z","shell.execute_reply":"2024-11-14T12:37:45.633129Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Decoder(nn.Module):\n\n    def __init__(self, encoder_dim=(32, 64, 128, 256), upscale=4, num_classes=1):\n\n        super(Decoder, self).__init__()\n\n        self.conv = nn.ModuleList([\n            nn.Sequential(\n                nn.Conv2d(encoder_dim[i] + encoder_dim[i - 1], encoder_dim[i - 1], 3, 1, 1, bias=False),\n                nn.BatchNorm2d(encoder_dim[i - 1]),\n                nn.ReLU(inplace=True)\n            ) for i in range(1, len(encoder_dim))\n        ])\n\n        self.logit = nn.Conv2d(encoder_dim[0], num_classes, 1, 1, 0)\n        self.up = nn.Upsample(scale_factor=upscale, mode='bilinear')\n\n    def forward(self, feature):\n\n        for i in range(len(feature) - 1, 0, -1):\n            f_up = F.interpolate(feature[i], scale_factor=2, mode='bilinear')\n            f = torch.cat([feature[i - 1], f_up], dim=1)\n            f_down = self.conv[i - 1](f)\n            feature[i - 1] = f_down\n\n        x = self.logit(feature[0])\n        out = self.up(x)\n\n        return out\nclass SegModel(nn.Module):\n\n    def __init__(self, num_classes):\n\n        super(SegModel, self).__init__()\n\n        self.encoder = timm.create_model(\n            'maxvit_tiny_tf_512.in1k',\n            features_only=True,\n            pretrained=False,\n            out_indices=[1, 2, 3, 4]\n        )\n\n        self.decoder = Decoder(\n            self.encoder.feature_info.channels(),\n            upscale=self.encoder.feature_info.reduction()[0],\n            num_classes=num_classes\n        )\n\n    def forward(self, x):\n\n        feat_maps = self.encoder(x)\n        logits = self.decoder(feat_maps)\n        masks = torch.sigmoid(logits)\n\n        return masks","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:00.705033Z","iopub.execute_input":"2024-11-14T12:38:00.706208Z","iopub.status.idle":"2024-11-14T12:38:00.72215Z","shell.execute_reply.started":"2024-11-14T12:38:00.706142Z","shell.execute_reply":"2024-11-14T12:38:00.720695Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class ClassificationHead(nn.Module):\n\n    def __init__(self, input_dimensions, cancer_output_dimensions):\n\n        super(ClassificationHead, self).__init__()\n\n        self.cancer_head = nn.Linear(input_dimensions, cancer_output_dimensions, bias=True)\n\n    def forward(self, x):\n\n        cancer_output = self.cancer_head(x)\n\n        return cancer_output\nclass TimmConvImageClassificationModel(nn.Module):\n\n    def __init__(self, model_name, pretrained, backbone_args, pooling_type, dropout_rate, freeze_parameters, head_args):\n\n        super(TimmConvImageClassificationModel, self).__init__()\n\n        self.backbone = timm.create_model(\n            model_name=model_name,\n            pretrained=pretrained,\n            **backbone_args\n        )\n\n        if freeze_parameters:\n            for parameter in self.backbone.parameters():\n                parameter.requires_grad = False\n\n        input_features = self.backbone.get_classifier().in_features\n\n        self.pooling_type = pooling_type\n        self.dropout = nn.Dropout(dropout_rate) if dropout_rate > 0 else nn.Identity()\n        self.head = ClassificationHead(input_dimensions=input_features, **head_args)\n    def forward(self, x):\n\n        x = self.backbone.forward_features(x)\n\n        if self.pooling_type == 'avg':\n            x = F.adaptive_avg_pool2d(x, output_size=(1, 1)).view(x.size(0), -1)\n        elif self.pooling_type == 'max':\n            x = F.adaptive_max_pool2d(x, output_size=(1, 1)).view(x.size(0), -1)\n        elif self.pooling_type == 'concat':\n            x = torch.cat([\n                F.adaptive_avg_pool2d(x, output_size=(1, 1)).view(x.size(0), -1),\n                F.adaptive_max_pool2d(x, output_size=(1, 1)).view(x.size(0), -1)\n            ], dim=-1)\n\n        x = self.dropout(x)\n        cancer_output = self.head(x)\n\n        return cancer_output\n        ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:04.660517Z","iopub.execute_input":"2024-11-14T12:38:04.66098Z","iopub.status.idle":"2024-11-14T12:38:04.677423Z","shell.execute_reply.started":"2024-11-14T12:38:04.660936Z","shell.execute_reply":"2024-11-14T12:38:04.675962Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_segmentation_model(model_directory, model_file_name, device):\n    \n    \"\"\"\n    Load model and pretrained weights from the given model directory\n\n    Parameters\n    ----------\n    model_directory: pathlib.Path\n        Path of the model directory\n\n    model_file_name: str\n        Name of the model weights file\n\n    device: torch.device\n        Location of the model\n\n    Returns\n    -------\n    model: torch.nn.Module\n        Model with weights loaded\n    \"\"\"\n\n    model = SegModel(num_classes=1)\n    model.load_state_dict(torch.load(model_directory / model_file_name), strict=True)\n    model.to(device)\n    model.eval()\n    print(f'{model.__class__.__name__} model\\'s weights are loaded from {model_directory / model_file_name}')\n\n    return model\ndef load_classification_model(model_directory, model_file_names, device):\n    \n    \"\"\"\n    Load model and pretrained weights from the given model directory\n\n    Parameters\n    ----------\n    model_directory: pathlib.Path\n        Path of the model directory\n\n    model_file_names: list\n        List of names of the model weights files\n\n    device: torch.device\n        Location of the model\n\n    Returns\n    -------\n    model: dict\n        Dictionary of models with weights loaded\n    \"\"\"\n\n    config = yaml.load(open(model_directory / 'config.yaml', 'r'), Loader=yaml.FullLoader)\n    config['model']['model_args']['pretrained'] = False\n        \n    models = {}\n    for model_file_name in model_file_names:\n        model = eval(config['model']['model_class'])(**config['model']['model_args'])\n        model.load_state_dict(torch.load(model_directory / model_file_name))\n        model.to(device)\n        model.eval()\n        models[model_file_name] = model\n        print(f'{model.__class__.__name__} model\\'s weights are loaded from {model_directory / model_file_name}')\n\n    return models, config\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:11.10441Z","iopub.execute_input":"2024-11-14T12:38:11.104883Z","iopub.status.idle":"2024-11-14T12:38:11.117008Z","shell.execute_reply.started":"2024-11-14T12:38:11.104823Z","shell.execute_reply":"2024-11-14T12:38:11.115702Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"segmentation_model = load_segmentation_model(\n    model_directory=external_dataset / 'segmentation',\n    model_file_name='maxvit_tiny_512_v1_final_epoch_13.pt',\n    device=torch.device('cuda')\n)\n\nmodels, config = load_classification_model(\n    model_directory=external_dataset / 'efficientnetv2s_1024_crop_16_v2.1',\n    model_file_names=[\n        'model_fold1_epoch_8.pt',\n        'model_fold2_epoch_15.pt',\n        'model_fold3_epoch_15.pt',\n        'model_fold4_epoch_15.pt',\n        'model_fold5_epoch_14.pt',\n    ],\n    device=torch.device('cuda')\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:31:09.028062Z","iopub.execute_input":"2024-11-14T12:31:09.028562Z","iopub.status.idle":"2024-11-14T12:31:11.200809Z","shell.execute_reply.started":"2024-11-14T12:31:09.028517Z","shell.execute_reply":"2024-11-14T12:31:11.198824Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nprint(torch.cuda.is_available())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:29.456507Z","iopub.execute_input":"2024-11-14T12:38:29.457005Z","iopub.status.idle":"2024-11-14T12:38:29.463082Z","shell.execute_reply.started":"2024-11-14T12:38:29.456958Z","shell.execute_reply":"2024-11-14T12:38:29.461902Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_segmentation_model(model_directory, model_file_name, device):\n    \"\"\"\n    Load model and pretrained weights from the given model directory\n\n    Args:\n        model_directory (Path): Path to the model directory\n        model_file_name (str): Name of the model file\n        device (torch.device): Device to load the model on\n\n    Returns:\n        Model with weights loaded\n    \"\"\"\n    # Create an instance of the model\n    model = SegModel(num_classes=1)\n\n    # Load model weights, mapping to the specified device\n    model.load_state_dict(\n        torch.load(\n            model_directory / model_file_name, \n            map_location=device,\n            weights_only=True  # Set weights_only to True\n        ),\n        strict=True\n    )\n\n    # Move model to the specified device\n    model.to(device)\n    model.eval()\n    return model\n\n# Example usage\nsegmentation_model = load_segmentation_model(\n    model_directory=external_dataset / 'segmentation',\n    model_file_name='maxvit_tiny_512_v1_final_epoch_13.pt',\n    device=torch.device('cpu')  # or 'cuda' if available\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:33.729806Z","iopub.execute_input":"2024-11-14T12:38:33.730309Z","iopub.status.idle":"2024-11-14T12:38:34.930361Z","shell.execute_reply.started":"2024-11-14T12:38:33.730263Z","shell.execute_reply":"2024-11-14T12:38:34.929061Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"segmentation_size = 384\nsegmentation_device = torch.device('cuda')\nsegmentation_amp = True\n\nsegmentation_transforms = A.Compose([\n    A.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5]),\n    ToTensorV2()\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:41.955095Z","iopub.execute_input":"2024-11-14T12:38:41.955576Z","iopub.status.idle":"2024-11-14T12:38:41.965454Z","shell.execute_reply.started":"2024-11-14T12:38:41.955531Z","shell.execute_reply":"2024-11-14T12:38:41.964372Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"classification_crop_size = 1024\nclassification_top_n_crops = 16\n\nclassification_device = torch.device('cuda')\nclassification_amp = True\n\ntta = False\ntta_flip_dimensions = [(2,), (3,), (2, 3)]\n\nclassification_transforms = A.Compose([\n    A.Resize(\n        height=1024,\n        width=1024,\n        interpolation=cv2.INTER_NEAREST,\n        always_apply=True\n    ),\n    A.Normalize(\n        mean=[0.485, 0.456, 0.406],\n        std=[0.229, 0.224, 0.225],\n        max_pixel_value=255,\n        always_apply=True\n    ),\n    ToTensorV2(always_apply=True)\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:45.912296Z","iopub.execute_input":"2024-11-14T12:38:45.912785Z","iopub.status.idle":"2024-11-14T12:38:45.924899Z","shell.execute_reply.started":"2024-11-14T12:38:45.912741Z","shell.execute_reply":"2024-11-14T12:38:45.923531Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_max_quo(num, div):\n    quo, rem = divmod(num, div)\n    max_quo = quo + 1 if rem > 0 else quo\n    return max_quo\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:50.863943Z","iopub.execute_input":"2024-11-14T12:38:50.864439Z","iopub.status.idle":"2024-11-14T12:38:50.870707Z","shell.execute_reply.started":"2024-11-14T12:38:50.864394Z","shell.execute_reply":"2024-11-14T12:38:50.869259Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport torch\nimport pandas as pd\n\n# Sample placeholders for functions. Replace these with your actual implementations.\ndef drop_low_std(image, threshold=10):\n    # Dummy implementation: remove white areas\n    std_dev = np.std(image, axis=(0, 1))\n    return image if np.any(std_dev > threshold) else np.zeros_like(image)\n\ndef read_image(image_path):\n    # Read an image from a file path\n    image = cv2.imread(image_path)\n    if image is None:\n        raise ValueError(f\"Image could not be read from {image_path}\")\n    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\ndef visualize_image(image, title, mask=None, path=None):\n    # Dummy visualization function\n    if mask is not None:\n        # Combine mask and image if mask is provided\n        combined_image = cv2.addWeighted(image, 0.5, mask, 0.5, 0)\n        cv2.imshow(title, combined_image)\n    else:\n        cv2.imshow(title, image)\n    if path is not None:\n        cv2.imwrite(path, image)\n    cv2.waitKey(0)\n    cv2.destroyAllWindows()\n\n# Placeholder for classification transforms, models, etc.\nclassification_device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nclassification_transforms = lambda x: {'image': torch.tensor(x).permute(2, 0, 1).float().to(classification_device)}\nclassification_amp = False  # Adjust according to your needs\ntta = False  # Adjust according to your needs\nmodels = {}  # Load your models here\nsegmentation_model = None  # Load your segmentation model here\nsegmentation_transforms = lambda x: {'image': torch.tensor(x).permute(2, 0, 1).float().to(classification_device)}\n\n# Define segmentation size and classification crop size\nsegmentation_size = 512  # Example segmentation size\nclassification_crop_size = 256  # Example classification crop size\n\n# Sample DataFrame (replace this with your actual DataFrame)\ndata = {\n    'image_id': ['img1', 'img2'],\n    'image_type': ['tma', 'thumbnail'],\n    'image_path': ['path_to_image1.jpg', 'path_to_thumbnail/img2_thumbnail.png']\n}\ndf = pd.DataFrame(data)\n\npredictions = []\nimage_ids = []\n\nfor idx, row in df.iterrows():\n    image_id = row['image_id']\n    image_type = row['image_type']\n    image_path = row['image_path']\n\n    if image_type == 'tma':\n        try:\n            if not os.path.isfile(image_path):\n                print(f\"File not found: {image_path}\")\n                continue  # Skip this iteration if the file doesn't exist\n            image = read_image(image_path)  # Using read_image function\n        except ValueError as e:\n            print(e)\n            continue  # Skip to the next image if there's an error\n\n        # Drop low standard deviation rows and columns (white areas with less tissue)\n        image = drop_low_std(image=image, threshold=10)\n\n        tma_predictions = torch.zeros(1, 6)\n\n        inputs = classification_transforms(image=image)['image']\n        inputs = inputs.to(classification_device)\n\n        if tta:\n            inputs = torch.stack((\n                inputs,\n                torch.flip(inputs, dims=(1,)),\n                torch.flip(inputs, dims=(2,)),\n                torch.flip(inputs, dims=(1, 2))\n            ), dim=0)\n        else:\n            inputs = torch.unsqueeze(inputs, dim=0)\n\n        for model_idx, models in enumerate([models]):\n            for model in models.values():\n                with torch.no_grad():\n                    if classification_amp:\n                        with torch.autocast(device_type='cuda', dtype=torch.float16):\n                            outputs = model(inputs)\n                    else:\n                        outputs = model(inputs)\n\n                outputs = outputs.cpu()\n                if tta:\n                    outputs = torch.mean(outputs, dim=0)\n                else:\n                    outputs = torch.squeeze(outputs, dim=0)\n\n                tma_predictions += outputs / len(models)\n\n        tma_predictions = torch.softmax(tma_predictions, dim=-1).numpy()\n        predictions.append(tma_predictions)\n        image_ids.append(np.array([image_id]))\n\n    else:\n        image_thumbnail_path = str('path_to_thumbnail/' + f'{image_id}_thumbnail.png')\n        try:\n            if not os.path.isfile(image_thumbnail_path):\n                print(f\"File not found: {image_thumbnail_path}\")\n                continue  # Skip this iteration if the file doesn't exist\n            image_thumbnail = read_image(image_thumbnail_path)  # Using read_image function\n        except ValueError as e:\n            print(e)\n            continue  # Skip to the next image if there's an error\n\n        image_thumbnail_height, image_thumbnail_width = image_thumbnail.shape[:2]\n        thumbnail_height_padding = segmentation_size - image_thumbnail_height % segmentation_size\n        thumbnail_width_padding = segmentation_size - image_thumbnail_width % segmentation_size\n        image_thumbnail_padded = np.pad(image_thumbnail, ((0 + 64, thumbnail_height_padding + 64), (0 + 64, thumbnail_width_padding + 64), (0, 0)))\n        mask_padded = np.zeros((image_thumbnail_height + thumbnail_height_padding, image_thumbnail_width + thumbnail_width_padding), dtype=np.float32)\n\n        for height in range((image_thumbnail_height + thumbnail_height_padding) // segmentation_size):\n            height_1, height_2 = height * segmentation_size, (height + 1) * segmentation_size\n            for width in range((image_thumbnail_width + thumbnail_width_padding) // segmentation_size):\n                width_1, width_2 = width * segmentation_size, (width + 1) * segmentation_size\n\n                image_thumbnail_tile = image_thumbnail_padded[height_1:height_2 + 128, width_1:width_2 + 128]\n                inputs = segmentation_transforms(image=image_thumbnail_tile)['image'].to(classification_device)\n                inputs = torch.stack((\n                    inputs,\n                    torch.flip(inputs, dims=(1,)),\n                    torch.flip(inputs, dims=(2,)),\n                    torch.flip(inputs, dims=(1, 2))\n                ), dim=0)\n\n                with torch.no_grad():\n                    if segmentation_amp:\n                        with torch.autocast(device_type='cuda', dtype=torch.float16):\n                            outputs = segmentation_model(inputs)\n                    else:\n                        outputs = segmentation_model(inputs)\n\n                outputs = outputs.cpu()\n                outputs = torch.stack((\n                    outputs[0],\n                    torch.flip(outputs[1], dims=(1,)),\n                    torch.flip(outputs[2], dims=(2,)),\n                    torch.flip(outputs[3], dims=(1, 2)),\n                ), dim=0)\n                outputs = torch.mean(outputs, dim=0).squeeze().cpu().numpy()\n                mask_padded[height_1:height_2, width_1:width_2] = outputs[64:448, 64:448]\n\n        mask = mask_padded[:image_thumbnail_height, :image_thumbnail_width]\n        # Extract image size from the image headers (example placeholder)\n        image_width, image_height = image_thumbnail.shape[1], image_thumbnail.shape[0]  # Assuming you get the original size from somewhere\n        mask = np.uint8(mask * 255)\n        mask = cv2.resize(mask, (image_width, image_height), cv2.INTER_NEAREST)\n\n        image_height_max_quotient = image_height // classification_crop_size\n        image_width_max_quotient = image_width // classification_crop_size\n        crops = []\n\n        for h in range(image_height_max_quotient):\n            for w in range(image_width_max_quotient):\n                width_2, height_2 = min(image_width, (w + 1) * classification_crop_size), min(image_height, (h + 1) * classification_crop_size)\n                width_1, height_1 = width_2 - classification_crop_size, height_2 - classification_crop_size\n\n                mask_crop = mask[height_1:height_2, width_1:width_2]\n                area = np.sum(mask_crop) / 255.0\n                crops.append([area, width_1, height_1, width_2, height_2])\n\n        # Sort crops by mask area in descending order\n        crops = np.array(crops)\n        crops = crops[crops[:, 0].argsort()[::-1]].astype(np.int32)\n\n        image = read_image(image_path=image_path)\n        image_crops = []\n\n        # Crop the raw image\n        for crop_idx, crop in enumerate(crops[:5]):  # Assuming you want top 5 crops\n            area, width_1, height_1, width_2, height_2 = crop\n            image_crops.append(image[height_1:height_2, width_1:width_2, :].copy())\n\n        crop_predictions = torch.zeros(len(image_crops), 6)\n        for crop_idx, image_crop in enumerate(image_crops):\n            inputs = classification_transforms(image=image_crop)['image']\n            inputs = inputs.to(classification_device)\n\n            if tta:\n                inputs = torch.stack((\n                    inputs,\n                    torch.flip(inputs, dims=(1,)),\n                    torch.flip(inputs, dims=(2,)),\n                    torch.flip(inputs, dims=(1, 2))\n                ), dim=0)\n            else:\n                inputs = torch.unsqueeze(inputs, dim=0)\n\n            for model_idx, models in enumerate([models]):\n                for model in models.values():\n                    with torch.no_grad():\n                        if classification_amp:\n                            with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                outputs = model(inputs)\n                        else:\n                            outputs = model(inputs)\n\n                    outputs = outputs.cpu()\n                    if tta:\n                        outputs = torch.mean(outputs, dim=0)\n                    else:\n                        outputs = torch.squeeze(outputs, dim=0)\n\n                    crop_predictions[crop_idx] += outputs / len(models)\n\n        crop_predictions = torch.softmax(crop_predictions, dim=-1).numpy()\n        predictions.append(crop_predictions)\n        image_ids.append(np.array([image_id] * len(crop_predictions)))\n\n# After processing all images\nif predictions:\n    predictions = np.concatenate(predictions)\n    image_ids = np.concatenate(image_ids)\nelse:\n    print(\"No predictions were made.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:38:54.626393Z","iopub.execute_input":"2024-11-14T12:38:54.627068Z","iopub.status.idle":"2024-11-14T12:38:54.686189Z","shell.execute_reply.started":"2024-11-14T12:38:54.627001Z","shell.execute_reply":"2024-11-14T12:38:54.684957Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torch\nimport cv2\nfrom torchvision import transforms\nfrom PIL import Image\n\n# Define your transforms here (update as needed)\ndef classification_transforms(image):\n    \"\"\"\n    Apply necessary transformations for classification.\n\n    Args:\n        image (numpy.ndarray): The input image.\n\n    Returns:\n        dict: Transformed image.\n    \"\"\"\n    transform = transforms.Compose([\n        transforms.ToPILImage(),\n        transforms.Resize((224, 224)),  # Adjust size as necessary\n        transforms.ToTensor()\n    ])\n    return {'image': transform(image)}\n\n# Function to drop low standard deviation areas from the image\ndef drop_low_std(image, threshold):\n    \"\"\"\n    Drop areas in the image with low standard deviation.\n\n    Args:\n        image (numpy.ndarray): The input image.\n        threshold (float): The threshold for standard deviation.\n\n    Returns:\n        numpy.ndarray: Processed image.\n    \"\"\"\n    std_dev = image.std(axis=(0, 1))\n    mask = std_dev > threshold\n    return image if mask.any() else np.zeros_like(image)\n\n# Function to visualize images (for debugging)\ndef visualize_image(image, title='', mask=None, path=None):\n    \"\"\"\n    Visualize an image.\n\n    Args:\n        image (numpy.ndarray): The image to visualize.\n        title (str): Title for the visualization.\n        mask (numpy.ndarray, optional): Mask to overlay on the image.\n        path (str, optional): Path to save the visualized image.\n    \"\"\"\n    # If mask is provided, overlay it on the image\n    if mask is not None:\n        image = cv2.addWeighted(image, 0.7, mask, 0.3, 0)\n    cv2.imshow(title, image)\n    if path:\n        cv2.imwrite(path, image)\n    cv2.waitKey(0)\n    cv2.destroyAllWindows()\n\n# Function to read an image\ndef read_image(image_path):\n    \"\"\"\n    Read an image from a file.\n\n    Args:\n        image_path (str): Path to the image file.\n\n    Returns:\n        numpy.ndarray: The loaded image.\n    \"\"\"\n    image = cv2.imread(image_path)\n    if image is None:\n        raise ValueError(f\"Could not open or find the image at path: {image_path}\")\n    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n# Function to get the maximum quotient for dimensions\ndef get_max_quo(dim_size, crop_size):\n    \"\"\"\n    Get the maximum quotient of the dimension size by the crop size.\n\n    Args:\n        dim_size (int): Dimension size.\n        crop_size (int): Crop size.\n\n    Returns:\n        int: Maximum quotient.\n    \"\"\"\n    return dim_size // crop_size\n\n# Main execution\nif __name__ == \"__main__\":\n    # Replace with your actual DataFrame creation/loading logic\n    df = pd.DataFrame({\n        'image_id': ['img1', 'img2'],\n        'image_type': ['tma', 'thumbnail'],\n        'image_path': ['path_to_image1.jpg', 'path_to_image2.jpg']  # Update these paths accordingly\n    })\n\n    predictions = []\n    image_ids = []\n    classification_device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    classification_amp = False  # Adjust as needed\n    tta = False  # Adjust as needed\n    segmentation_size = 512  # Example value, adjust based on your use case\n    classification_crop_size = 224  # Example value, adjust based on your use case\n    models = {}  # Replace with your model loading logic\n\n    for idx, row in df.iterrows():\n        image_id = row['image_id']\n        image_type = row['image_type']\n        image_path = row['image_path']\n\n        if image_type == 'tma':\n            try:\n                image = read_image(image_path)  # Using read_image function\n            except ValueError as e:\n                print(e)\n                continue  # Skip to the next image if there's an error\n\n            # Drop low standard deviation rows and columns (white areas with less tissue)\n            image = drop_low_std(image=image, threshold=10)\n\n            tma_predictions = torch.zeros(1, 6)\n\n            inputs = classification_transforms(image=image)['image']\n            inputs = inputs.to(classification_device)\n\n            if tta:\n                inputs = torch.stack((\n                    inputs,\n                    torch.flip(inputs, dims=(1,)),\n                    torch.flip(inputs, dims=(2,)),\n                    torch.flip(inputs, dims=(1, 2))\n                ), dim=0)\n            else:\n                inputs = torch.unsqueeze(inputs, dim=0)\n\n            for model_idx, models in enumerate([models]):\n                for model in models.values():\n                    with torch.no_grad():\n                        if classification_amp:\n                            with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                outputs = model(inputs)\n                        else:\n                            outputs = model(inputs)\n\n                    outputs = outputs.cpu()\n                    if tta:\n                        outputs = torch.mean(outputs, dim=0)\n                    else:\n                        outputs = torch.squeeze(outputs, dim=0)\n\n                    tma_predictions += outputs / len(models)\n\n            tma_predictions = torch.softmax(tma_predictions, dim=-1).numpy()\n            predictions.append(tma_predictions)\n            image_ids.append(np.array([image_id]))\n\n        else:\n            image_thumbnail_path = str('path_to_thumbnail/' + f'{image_id}_thumbnail.png')\n            try:\n                image_thumbnail = read_image(image_thumbnail_path)  # Using read_image function\n            except ValueError as e:\n                print(e)\n                continue  # Skip to the next image if there's an error\n\n            print(f'Image {image_id} {image_thumbnail.shape} thumbnail is loaded from {image_thumbnail_path}')\n\n            image_thumbnail_height, image_thumbnail_width = image_thumbnail.shape[:2]\n            thumbnail_height_padding = segmentation_size - image_thumbnail_height % segmentation_size\n            thumbnail_width_padding = segmentation_size - image_thumbnail_width % segmentation_size\n            image_thumbnail_padded = np.pad(image_thumbnail, ((64, thumbnail_height_padding + 64), (64, thumbnail_width_padding + 64), (0, 0)))\n            mask_padded = np.zeros((image_thumbnail_height + thumbnail_height_padding, image_thumbnail_width + thumbnail_width_padding), dtype=np.float32)\n\n            print(f'Image {image_id} {image_thumbnail_padded.shape} thumbnail and mask {mask_padded.shape} are padded')\n\n            for height in range((image_thumbnail_height + thumbnail_height_padding) // segmentation_size):\n                height_1, height_2 = height * segmentation_size, (height + 1) * segmentation_size\n                for width in range((image_thumbnail_width + thumbnail_width_padding) // segmentation_size):\n                    width_1, width_2 = width * segmentation_size, (width + 1) * segmentation_size\n\n                    image_thumbnail_tile = image_thumbnail_padded[height_1:height_2 + 128, width_1:width_2 + 128]\n                    inputs = classification_transforms(image=image_thumbnail_tile)['image'].to(classification_device)\n                    inputs = torch.stack((\n                        inputs,\n                        torch.flip(inputs, dims=(1,)),\n                        torch.flip(inputs, dims=(2,)),\n                        torch.flip(inputs, dims=(1, 2))\n                    ), dim=0)\n\n                    with torch.no_grad():\n                        if classification_amp:\n                            with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                outputs = model(inputs)\n                        else:\n                            outputs = model(inputs)\n\n                    outputs = outputs.cpu()\n                    outputs = torch.stack((\n                        outputs[0],\n                        torch.flip(outputs[1], dims=(1,)),\n                        torch.flip(outputs[2], dims=(2,)),\n                        torch.flip(outputs[3], dims=(1, 2)),\n                    ), dim=0)\n                    outputs = torch.mean(outputs, dim=0).squeeze().cpu().numpy()\n                    mask_padded[height_1:height_2, width_1:width_2] = outputs[64:448, 64:448]\n\n                    print(f'Predicted x ({width_1}-{width_2}) y ({height_1}-{height_2})')\n\n            mask = mask_padded[:image_thumbnail_height, :image_thumbnail_width]\n            del mask_padded\n\n            print(f'Image {image_id} {mask.shape} mask is predicted')\n            image_width, image_height = image_thumbnail.shape[1], image_thumbnail.shape[0]\n\n            # Cast mask soft predictions to 8-bit integer and upsample\n            mask = np.uint8(mask * 255)\n            mask = cv2.resize(mask, (image_width, image_height), cv2.INTER_NEAREST)\n\n            print(f'Image {image_id} mask {mask.shape} is upsampled')\n\n            image_height_max_quotient = get_max_quo(image_height, classification_crop_size)\n            image_width_max_quotient = get_max_quo(image_width, classification_crop_size)\n            crops = []\n\n            for h in range(image_height_max_quotient):\n                for w in range(image_width_max_quotient):\n                    width_2, height_2 = min(image_width, (w + 1) * classification_crop_size), min(image_height, (h + 1) * classification_crop_size)\n                    width_1, height_1 = width_2 - classification_crop_size, height_2 - classification_crop_size\n\n                    crops.append((mask[height_1:height_2, width_1:width_2], width_1, height_1, width_2, height_2))\n\n            crops = np.array(crops)\n            crops = crops[np.argsort(crops[:, 0].mean(axis=(1,)), axis=0)[::-1]].astype(np.int32)\n\n            print(f'{crops.shape[0]} crops are extracted from the mask')\n\n            # Crop the raw image and delete it\n            image_crops = []\n            for crop_idx, crop in enumerate(crops[:classification_crop_size]):\n                area, width_1, height_1, width_2, height_2 = crop\n                image_crops.append(image_thumbnail[height_1:height_2, width_1:width_2, :].copy())\n            del image_thumbnail\n\n            crop_predictions = torch.zeros(len(image_crops), 6)\n            for crop_idx, image_crop in enumerate(image_crops):\n                print(f'Image {image_id} crop {crop_idx}')\n                inputs = classification_transforms(image=image_crop)['image']\n                inputs = inputs.to(classification_device)\n\n                if tta:\n                    inputs = torch.stack((\n                        inputs,\n                        torch.flip(inputs, dims=(1,)),\n                        torch.flip(inputs, dims=(2,)),\n                        torch.flip(inputs, dims=(1, 2))\n                    ), dim=0)\n                else:\n                    inputs = torch.unsqueeze(inputs, dim=0)\n\n                for model_idx, models in enumerate([models]):\n                    for model in models.values():\n                        with torch.no_grad():\n                            if classification_amp:\n                                with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                    outputs = model(inputs)\n                            else:\n                                outputs = model(inputs)\n\n                        outputs = outputs.cpu()\n                        if tta:\n                            outputs = torch.mean(outputs, dim=0)\n                        else:\n                            outputs = torch.squeeze(outputs, dim=0)\n\n                        crop_predictions[crop_idx] += outputs / len(models)\n\n            crop_predictions = torch.softmax(crop_predictions, dim=-1).numpy()\n            predictions.append(crop_predictions)\n            image_ids.append(np.array([image_id] * len(crop_predictions)))\n\n    predictions = np.concatenate(predictions)\n    image_ids = np.concatenate(image_ids)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:32:29.52195Z","iopub.execute_input":"2024-11-14T12:32:29.522389Z","iopub.status.idle":"2024-11-14T12:32:29.756389Z","shell.execute_reply.started":"2024-11-14T12:32:29.522348Z","shell.execute_reply":"2024-11-14T12:32:29.754529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport numpy as np\nimport torch\nimport pandas as pd\nimport imagesize\nfrom pathlib import Path\n\n# Assume these functions are defined elsewhere in your code\n# from your_module import drop_low_std, classification_transforms, visualize_image, read_image, get_max_quo\n\n# Initialize required variables\nclassification_device = 'cuda' if torch.cuda.is_available() else 'cpu'\nsegmentation_device = classification_device\nclassification_top_n_crops = 5  # Adjust as necessary\nsegmentation_size = 512  # Example segmentation size\ntta = True  # Test Time Augmentation flag\nclassification_amp = True  # Mixed precision flag\nsegmentation_amp = True  # Mixed precision flag\npredictions = []\nimage_ids = []\n\n# Main processing loop\nfor idx, row in df.iterrows():\n    image_id = row['image_id']\n    image_type = row['image_type']\n    image_path = row['image_path']\n\n    if image_type == 'tma':\n        image = cv2.imread(image_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n        # Drop low standard deviation rows and columns (white areas with less tissue)\n        image = drop_low_std(image=image, threshold=10)\n\n        tma_predictions = torch.zeros(1, 6)\n\n        inputs = classification_transforms(image=image)['image']\n        inputs = inputs.to(classification_device)\n\n        # Convert inputs to float32 to match model parameters\n        inputs = inputs.float()\n\n        if tta:\n            inputs = torch.stack((\n                inputs,\n                torch.flip(inputs, dims=(1,)),\n                torch.flip(inputs, dims=(2,)),\n                torch.flip(inputs, dims=(1, 2))\n            ), dim=0)\n        else:\n            inputs = torch.unsqueeze(inputs, dim=0)\n\n        for model_idx, models in enumerate([models]):\n            for model in models.values():\n                with torch.no_grad():\n                    if classification_amp:\n                        with torch.autocast(device_type='cuda' if torch.cuda.is_available() else 'cpu', dtype=torch.float16):\n                            outputs = model(inputs)\n                    else:\n                        outputs = model(inputs)\n\n                outputs = outputs.cpu()\n                if tta:\n                    outputs = torch.mean(outputs, dim=0)\n                else:\n                    outputs = torch.squeeze(outputs, dim=0)\n\n                tma_predictions += outputs / len(models)\n\n        tma_predictions = torch.softmax(tma_predictions, dim=-1).numpy()\n        predictions.append(tma_predictions)\n        image_ids.append(np.array([image_id]))\n\n    else:\n        image_thumbnail_path = str(competition_dataset / 'test_thumbnails' / f'{image_id}_thumbnail.png')\n        image_thumbnail = cv2.imread(image_thumbnail_path)\n        image_thumbnail = cv2.cvtColor(image_thumbnail, cv2.COLOR_BGR2RGB)\n\n        if is_submission is False:\n            print(f'Image {image_id} {image_thumbnail.shape} thumbnail is loaded from {image_thumbnail_path}')\n            visualize_image(image=image_thumbnail, title=f'Image {image_id} Thumbnail {image_thumbnail.shape}', path='./thumbnail_raw.png')\n\n        image_thumbnail_height, image_thumbnail_width = image_thumbnail.shape[:2]\n        thumbnail_height_padding = segmentation_size - image_thumbnail_height % segmentation_size\n        thumbnail_width_padding = segmentation_size - image_thumbnail_width % segmentation_size\n        image_thumbnail_padded = np.pad(image_thumbnail, ((0 + 64, thumbnail_height_padding + 64), (0 + 64, thumbnail_width_padding + 64), (0, 0)))\n        mask_padded = np.zeros((image_thumbnail_height + thumbnail_height_padding, image_thumbnail_width + thumbnail_width_padding), dtype=np.float32)\n\n        if is_submission is False:\n            print(f'Image {image_id} {image_thumbnail_padded.shape} thumbnail and mask {mask_padded.shape} are padded')\n            visualize_image(image=image_thumbnail_padded, title=f'Image {image_id} Thumbnail Padded {image_thumbnail_padded.shape}', path='./thumbnail_padded.png')\n\n        for height in range((image_thumbnail_height + thumbnail_height_padding) // segmentation_size):\n            height_1, height_2 = height * segmentation_size, (height + 1) * segmentation_size\n            for width in range((image_thumbnail_width + thumbnail_width_padding) // segmentation_size):\n                width_1, width_2 = width * segmentation_size, (width + 1) * segmentation_size\n\n                image_thumbnail_tile = image_thumbnail_padded[height_1:height_2 + 128, width_1:width_2 + 128]\n                inputs = segmentation_transforms(image=image_thumbnail_tile)['image'].to(segmentation_device)\n\n                # Ensure inputs are float32 to match model parameters\n                inputs = inputs.float()\n\n                inputs = torch.stack((\n                    inputs,\n                    torch.flip(inputs, dims=(1,)),\n                    torch.flip(inputs, dims=(2,)),\n                    torch.flip(inputs, dims=(1, 2))\n                ), dim=0)\n\n                with torch.no_grad():\n                    if segmentation_amp:\n                        with torch.autocast(device_type='cuda' if torch.cuda.is_available() else 'cpu', dtype=torch.float16):\n                            outputs = segmentation_model(inputs)\n                    else:\n                        outputs = segmentation_model(inputs)\n\n                outputs = outputs.cpu()\n                outputs = torch.stack((\n                    outputs[0],\n                    torch.flip(outputs[1], dims=(1,)),\n                    torch.flip(outputs[2], dims=(2,)),\n                    torch.flip(outputs[3], dims=(1, 2)),\n                ), dim=0)\n                outputs = torch.mean(outputs, dim=0).squeeze().cpu().numpy()\n\n                # Calculate center crop dynamically\n                crop_size = outputs.shape[0] // 2\n                outputs_cropped = outputs[crop_size - segmentation_size//2:crop_size + segmentation_size//2, crop_size - segmentation_size//2:crop_size + segmentation_size//2]\n\n                mask_padded[height_1:height_2, width_1:width_2] = outputs_cropped\n\n                if is_submission is False:\n                    print(f'Predicted x ({width_1}-{width_2}) y ({height_1}-{height_2})')\n\n        mask = mask_padded[:image_thumbnail_height, :image_thumbnail_width]\n        del mask_padded\n\n        if is_submission is False:\n            print(f'Image {image_id} {mask.shape} mask is predicted')\n            visualize_image(image=image_thumbnail, title=f'Image {image_id} Thumbnail and Mask {mask.shape}', mask=mask, path='./thumbnail_mask.png')\n\n        # Extract image size from the image headers\n        image_width, image_height = imagesize.get(image_path)\n        # Cast mask soft predictions to 8-bit integer and upsample\n        mask = np.uint8(mask * 255)\n        mask = cv2.resize(mask, (image_width, image_height), cv2.INTER_NEAREST)\n\n        if is_submission is False:\n            print(f'Image {image_id} mask {mask.shape} is upsampled')\n            visualize_image(image=mask, title=f'Image {image_id} Mask {mask.shape}', path='./resized_mask.png')\n\n        image_height_max_quotient = get_max_quo(image_height, classification_crop_size)\n        image_width_max_quotient = get_max_quo(image_width, classification_crop_size)\n        crops = []\n\n        for h in range(image_height_max_quotient):\n            for w in range(image_width_max_quotient):\n                width_2, height_2 = min(image_width, (w + 1) * classification_crop_size), min(image_height, (h + 1) * classification_crop_size)\n                width_1, height_1 = width_2 - classification_crop_size, height_2 - classification_crop_size\n\n                mask_crop = mask[height_1:height_2, width_1:width_2]\n                area = np.sum(mask_crop) / 255.0\n                crops.append([area, width_1, height_1, width_2, height_2])\n\n        del mask\n        image = read_image(image_path=image_path)\n        image_crops = []\n\n        # Sort crops by mask area in descending order\n        crops = np.array(crops)\n        crops = crops[crops[:, 0].argsort()[::-1]].astype(np.int32)\n\n        if is_submission is False:\n            print(f'{crops.shape[0]} crops are extracted from the mask')\n\n        # Crop the raw image and delete it\n        for crop_idx, crop in enumerate(crops[:classification_top_n_crops]):\n            area, width_1, height_1, width_2, height_2 = crop\n            image_crops.append(image[height_1:height_2, width_1:width_2, :].copy())\n            del image\n\n            crop_predictions = torch.zeros(classification_top_n_crops, 6)\n            for crop_idx, image_crop in enumerate(image_crops):\n\n                if is_submission is False:\n                    print(f'Image {image_id} crop {crop_idx}')\n                    visualize_image(image=image_crop, title=f'Image {image_id} Crop {crop_idx}', path=f'./cropped_{crop_idx}.png')\n\n                inputs = classification_transforms(image=image_crop)['image']\n                inputs = inputs.to(classification_device)\n\n                # Ensure inputs are float32 to match model parameters\n                inputs = inputs.float()\n\n                if tta:\n                    inputs = torch.stack((\n                        inputs,\n                        torch.flip(inputs, dims=(1,)),\n                        torch.flip(inputs, dims=(2,)),\n                        torch.flip(inputs, dims=(1, 2))\n                    ), dim=0)\n                else:\n                    inputs = torch.unsqueeze(inputs, dim=0)\n\n                for model_idx, models in enumerate([models]):\n                    for model in models.values():\n                        with torch.no_grad():\n                            if classification_amp:\n                                with torch.autocast(device_type='cuda' if torch.cuda.is_available() else 'cpu', dtype=torch.float16):\n                                    outputs = model(inputs)\n                            else:\n                                outputs = model(inputs)\n\n                        outputs = outputs.cpu()\n                        if tta:\n                            outputs = torch.mean(outputs, dim=0)\n                        else:\n                            outputs = torch.squeeze(outputs, dim=0)\n\n                        crop_predictions[crop_idx] += outputs / len(models)\n\n            crop_predictions = torch.softmax(crop_predictions, dim=-1).numpy()\n            predictions.append(crop_predictions)\n            image_ids.append(np.array([image_id] * classification_top_n_crops))\n\n# Final concatenation\npredictions = np.concatenate(predictions)\nimage_ids = np.concatenate(image_ids)\n\n# Creating the DataFrame for results\ndf_predictions = pd.DataFrame(data=image_ids, columns=['image_id'])\n\n# Label mapping\nlabel_mapping = {\n    0: 'HGSC',\n    1: 'EC',\n    2: 'CC',\n    3: 'LGSC',\n    4: 'MC',\n    5: 'Other',\n}\n\n# Adding predictions to the DataFrame\nfor label_idx, label in label_mapping.items():\n    df_predictions[f'{label}_prediction'] = predictions[:, label_idx]\n\n# Display the DataFrame\nprint(df_predictions)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:13.233704Z","iopub.execute_input":"2024-11-14T12:33:13.234281Z","iopub.status.idle":"2024-11-14T12:33:13.485598Z","shell.execute_reply.started":"2024-11-14T12:33:13.23423Z","shell.execute_reply":"2024-11-14T12:33:13.483879Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Part 1: Utility Functions\n\nimport numpy as np\nimport pandas as pd\nimport torch\n\ndef get_max_quo(num, div):\n    \"\"\"\n    Calculate the maximum quotient when dividing num by div.\n\n    Parameters:\n    num (int): The numerator.\n    div (int): The denominator.\n\n    Returns:\n    int: The maximum quotient (num // div) + 1 if there's a remainder, else (num // div).\n    \"\"\"\n    quo, rem = divmod(num, div)\n    max_quo = quo + 1 if rem > 0 else quo\n    return max_quo\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:22.329189Z","iopub.execute_input":"2024-11-14T12:33:22.329647Z","iopub.status.idle":"2024-11-14T12:33:22.34046Z","shell.execute_reply.started":"2024-11-14T12:33:22.329603Z","shell.execute_reply":"2024-11-14T12:33:22.339314Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Part 2: Image Processing and Crop Extraction\n\ndef extract_crops(image, crops, classification_top_n_crops):\n    \"\"\"\n    Extract crops from the image based on the provided crop coordinates.\n\n    Parameters:\n    image (numpy.ndarray): The original image.\n    crops (numpy.ndarray): Array of crop coordinates.\n    classification_top_n_crops (int): Number of top crops to extract.\n\n    Returns:\n    list: List of image crops.\n    \"\"\"\n    image_crops = []\n    \n    # Sort crops by mask area in descending order\n    crops = np.array(crops)\n    crops = crops[crops[:, 0].argsort()[::-1]].astype(np.int32)\n\n    print(f'{crops.shape[0]} crops are extracted from the mask')\n\n    # Crop the raw image\n    for crop_idx, crop in enumerate(crops[:classification_top_n_crops]):\n        area, width_1, height_1, width_2, height_2 = crop\n        image_crops.append(image[height_1:height_2, width_1:width_2, :].copy())\n\n    return image_crops\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:27.498503Z","iopub.execute_input":"2024-11-14T12:33:27.499306Z","iopub.status.idle":"2024-11-14T12:33:27.507745Z","shell.execute_reply.started":"2024-11-14T12:33:27.499253Z","shell.execute_reply":"2024-11-14T12:33:27.506241Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Part 3: Model Predictions\n\ndef make_predictions(image_crops, model, classification_device, classification_amp, tta):\n    \"\"\"\n    Make predictions on the image crops using the provided model.\n\n    Parameters:\n    image_crops (list): List of cropped images.\n    model (torch.nn.Module): The model for making predictions.\n    classification_device (torch.device): The device to perform calculations on.\n    classification_amp (bool): Whether to use automatic mixed precision.\n    tta (bool): Whether to apply test time augmentation.\n\n    Returns:\n    np.ndarray: Predictions for the crops.\n    \"\"\"\n    predictions = []\n\n    for crop_idx, image_crop in enumerate(image_crops):\n        inputs = classification_transforms(image=image_crop)['image']\n        inputs = inputs.to(classification_device).float()  # Ensure inputs are float32\n\n        # Prepare for Test Time Augmentation (TTA)\n        if tta:\n            inputs = torch.stack((\n                inputs,\n                torch.flip(inputs, dims=(1,)),\n                torch.flip(inputs, dims=(2,)),\n                torch.flip(inputs, dims=(1, 2))\n            ), dim=0)\n        else:\n            inputs = torch.unsqueeze(inputs, dim=0)\n\n        with torch.no_grad():\n            if classification_amp:\n                with torch.autocast(device_type='cuda' if torch.cuda.is_available() else 'cpu', dtype=torch.float16):\n                    outputs = model(inputs)\n            else:\n                outputs = model(inputs)\n\n        outputs = outputs.cpu()\n        predictions.append(outputs)\n\n    return np.concatenate(predictions)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:32.057954Z","iopub.execute_input":"2024-11-14T12:33:32.058409Z","iopub.status.idle":"2024-11-14T12:33:32.070315Z","shell.execute_reply.started":"2024-11-14T12:33:32.058368Z","shell.execute_reply":"2024-11-14T12:33:32.069045Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Part 4: Creating and Displaying Predictions DataFrame\n\ndef create_predictions_dataframe(predictions, image_ids):\n    \"\"\"\n    Create a DataFrame for predictions.\n\n    Parameters:\n    predictions (np.ndarray): Array of predictions.\n    image_ids (np.ndarray): Corresponding image IDs.\n\n    Returns:\n    pd.DataFrame: DataFrame containing image IDs and predictions.\n    \"\"\"\n    df_predictions = pd.DataFrame(data=image_ids, columns=['image_id'])\n\n    # Label mapping\n    label_mapping = {\n        0: 'HGSC',\n        1: 'EC',\n        2: 'CC',\n        3: 'LGSC',\n        4: 'MC',\n        5: 'Other',\n    }\n\n    # Add predictions to the DataFrame\n    for label_idx, label in label_mapping.items():\n        df_predictions[f'{label}_prediction'] = predictions[:, label_idx]\n\n    return df_predictions\n\n# Example of usage:\n# df_predictions = create_predictions_dataframe(predictions, image_ids)\n# print(df_predictions)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:36.063656Z","iopub.execute_input":"2024-11-14T12:33:36.064132Z","iopub.status.idle":"2024-11-14T12:33:36.072565Z","shell.execute_reply.started":"2024-11-14T12:33:36.064091Z","shell.execute_reply":"2024-11-14T12:33:36.07124Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport torch\nimport cv2\nfrom torchvision import transforms\nfrom PIL import Image\n\n# Define your transforms here (update as needed)\ndef classification_transforms(image):\n    \"\"\"\n    Apply necessary transformations for classification.\n\n    Args:\n        image (numpy.ndarray): The input image.\n\n    Returns:\n        dict: Transformed image.\n    \"\"\"\n    transform = transforms.Compose([\n        transforms.ToPILImage(),\n        transforms.Resize((224, 224)),  # Adjust size as necessary\n        transforms.ToTensor()\n    ])\n    return {'image': transform(image)}\n\n# Function to drop low standard deviation areas from the image\ndef drop_low_std(image, threshold):\n    \"\"\"\n    Drop areas in the image with low standard deviation.\n\n    Args:\n        image (numpy.ndarray): The input image.\n        threshold (float): The threshold for standard deviation.\n\n    Returns:\n        numpy.ndarray: Processed image.\n    \"\"\"\n    std_dev = image.std(axis=(0, 1))\n    mask = std_dev > threshold\n    return image if mask.any() else np.zeros_like(image)\n\n# Function to visualize images (for debugging)\ndef visualize_image(image, title='', mask=None, path=None):\n    \"\"\"\n    Visualize an image.\n\n    Args:\n        image (numpy.ndarray): The image to visualize.\n        title (str): Title for the visualization.\n        mask (numpy.ndarray, optional): Mask to overlay on the image.\n        path (str, optional): Path to save the visualized image.\n    \"\"\"\n    # If mask is provided, overlay it on the image\n    if mask is not None:\n        image = cv2.addWeighted(image, 0.7, mask, 0.3, 0)\n    cv2.imshow(title, image)\n    if path:\n        cv2.imwrite(path, image)\n    cv2.waitKey(0)\n    cv2.destroyAllWindows()\n\n# Function to read an image\ndef read_image(image_path):\n    \"\"\"\n    Read an image from a file.\n\n    Args:\n        image_path (str): Path to the image file.\n\n    Returns:\n        numpy.ndarray: The loaded image.\n    \"\"\"\n    image = cv2.imread(image_path)\n    return cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n# Function to get the maximum quotient for dimensions\ndef get_max_quo(dim_size, crop_size):\n    \"\"\"\n    Get the maximum quotient of the dimension size by the crop size.\n\n    Args:\n        dim_size (int): Dimension size.\n        crop_size (int): Crop size.\n\n    Returns:\n        int: Maximum quotient.\n    \"\"\"\n    return dim_size // crop_size\n\n# Main execution\nif __name__ == \"__main__\":\n    # Replace with your actual DataFrame creation/loading logic\n    df = pd.DataFrame({\n        'image_id': ['img1', 'img2'],\n        'image_type': ['tma', 'thumbnail'],\n        'image_path': ['path_to_image1.jpg', 'path_to_image2.jpg']\n    })\n\n    predictions = []\n    image_ids = []\n    classification_device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    classification_amp = False  # Adjust as needed\n    tta = False  # Adjust as needed\n    segmentation_size = 512  # Example value, adjust based on your use case\n    classification_crop_size = 224  # Example value, adjust based on your use case\n    models = {}  # Replace with your model loading logic\n\n    for idx, row in df.iterrows():\n        image_id = row['image_id']\n        image_type = row['image_type']\n        image_path = row['image_path']\n\n        if image_type == 'tma':\n            image = cv2.imread(image_path)\n            image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n\n            # Drop low standard deviation rows and columns (white areas with less tissue)\n            image = drop_low_std(image=image, threshold=10)\n\n            tma_predictions = torch.zeros(1, 6)\n\n            inputs = classification_transforms(image=image)['image']\n            inputs = inputs.to(classification_device)\n\n            if tta:\n                inputs = torch.stack((\n                    inputs,\n                    torch.flip(inputs, dims=(1,)),\n                    torch.flip(inputs, dims=(2,)),\n                    torch.flip(inputs, dims=(1, 2))\n                ), dim=0)\n            else:\n                inputs = torch.unsqueeze(inputs, dim=0)\n\n            for model_idx, models in enumerate([models]):\n                for model in models.values():\n                    with torch.no_grad():\n                        if classification_amp:\n                            with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                outputs = model(inputs)\n                        else:\n                            outputs = model(inputs)\n\n                    outputs = outputs.cpu()\n                    if tta:\n                        outputs = torch.mean(outputs, dim=0)\n                    else:\n                        outputs = torch.squeeze(outputs, dim=0)\n\n                    tma_predictions += outputs / len(models)\n\n            tma_predictions = torch.softmax(tma_predictions, dim=-1).numpy()\n            predictions.append(tma_predictions)\n            image_ids.append(np.array([image_id]))\n\n        else:\n            image_thumbnail_path = str('path_to_thumbnail/' + f'{image_id}_thumbnail.png')\n            image_thumbnail = cv2.imread(image_thumbnail_path)\n            image_thumbnail = cv2.cvtColor(image_thumbnail, cv2.COLOR_BGR2RGB)\n\n            print(f'Image {image_id} {image_thumbnail.shape} thumbnail is loaded from {image_thumbnail_path}')\n\n            image_thumbnail_height, image_thumbnail_width = image_thumbnail.shape[:2]\n            thumbnail_height_padding = segmentation_size - image_thumbnail_height % segmentation_size\n            thumbnail_width_padding = segmentation_size - image_thumbnail_width % segmentation_size\n            image_thumbnail_padded = np.pad(image_thumbnail, ((64, thumbnail_height_padding + 64), (64, thumbnail_width_padding + 64), (0, 0)))\n            mask_padded = np.zeros((image_thumbnail_height + thumbnail_height_padding, image_thumbnail_width + thumbnail_width_padding), dtype=np.float32)\n\n            print(f'Image {image_id} {image_thumbnail_padded.shape} thumbnail and mask {mask_padded.shape} are padded')\n\n            for height in range((image_thumbnail_height + thumbnail_height_padding) // segmentation_size):\n                height_1, height_2 = height * segmentation_size, (height + 1) * segmentation_size\n                for width in range((image_thumbnail_width + thumbnail_width_padding) // segmentation_size):\n                    width_1, width_2 = width * segmentation_size, (width + 1) * segmentation_size\n\n                    image_thumbnail_tile = image_thumbnail_padded[height_1:height_2 + 128, width_1:width_2 + 128]\n                    inputs = classification_transforms(image=image_thumbnail_tile)['image'].to(classification_device)\n                    inputs = torch.stack((\n                        inputs,\n                        torch.flip(inputs, dims=(1,)),\n                        torch.flip(inputs, dims=(2,)),\n                        torch.flip(inputs, dims=(1, 2))\n                    ), dim=0)\n\n                    with torch.no_grad():\n                        if classification_amp:\n                            with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                outputs = model(inputs)\n                        else:\n                            outputs = model(inputs)\n\n                    outputs = outputs.cpu()\n                    outputs = torch.stack((\n                        outputs[0],\n                        torch.flip(outputs[1], dims=(1,)),\n                        torch.flip(outputs[2], dims=(2,)),\n                        torch.flip(outputs[3], dims=(1, 2)),\n                    ), dim=0)\n                    outputs = torch.mean(outputs, dim=0).squeeze().cpu().numpy()\n                    mask_padded[height_1:height_2, width_1:width_2] = outputs[64:448, 64:448]\n\n                    print(f'Predicted x ({width_1}-{width_2}) y ({height_1}-{height_2})')\n\n            mask = mask_padded[:image_thumbnail_height, :image_thumbnail_width]\n            del mask_padded\n\n            print(f'Image {image_id} {mask.shape} mask is predicted')\n            image_width, image_height = image_thumbnail.shape[1], image_thumbnail.shape[0]\n\n            # Cast mask soft predictions to 8-bit integer and upsample\n            mask = np.uint8(mask * 255)\n            mask = cv2.resize(mask, (image_width, image_height), cv2.INTER_NEAREST)\n\n            print(f'Image {image_id} mask {mask.shape} is upsampled')\n\n            image_height_max_quotient = get_max_quo(image_height, classification_crop_size)\n            image_width_max_quotient = get_max_quo(image_width, classification_crop_size)\n            crops = []\n\n            for h in range(image_height_max_quotient):\n                for w in range(image_width_max_quotient):\n                    width_2, height_2 = min(image_width, (w + 1) * classification_crop_size), min(image_height, (h + 1) * classification_crop_size)\n                    width_1, height_1 = width_2 - classification_crop_size, height_2 - classification_crop_size\n\n                    mask_crop = mask[height_1:height_2, width_1:width_2]\n                    area = np.sum(mask_crop) / 255.0\n                    crops.append([area, width_1, height_1, width_2, height_2])\n\n            del mask\n            image = read_image(image_path=image_path)\n            image_crops = []\n\n            # Sort crops by mask area in descending order\n            crops = np.array(crops)\n            crops = crops[crops[:, 0].argsort()[::-1]].astype(np.int32)\n\n            print(f'{crops.shape[0]} crops are extracted from the mask')\n\n            # Crop the raw image and delete it\n            for crop_idx, crop in enumerate(crops[:classification_crop_size]):\n                area, width_1, height_1, width_2, height_2 = crop\n                image_crops.append(image[height_1:height_2, width_1:width_2, :].copy())\n            del image\n\n            crop_predictions = torch.zeros(len(image_crops), 6)\n            for crop_idx, image_crop in enumerate(image_crops):\n                print(f'Image {image_id} crop {crop_idx}')\n                inputs = classification_transforms(image=image_crop)['image']\n                inputs = inputs.to(classification_device)\n\n                if tta:\n                    inputs = torch.stack((\n                        inputs,\n                        torch.flip(inputs, dims=(1,)),\n                        torch.flip(inputs, dims=(2,)),\n                        torch.flip(inputs, dims=(1, 2))\n                    ), dim=0)\n                else:\n                    inputs = torch.unsqueeze(inputs, dim=0)\n\n                for model_idx, models in enumerate([models]):\n                    for model in models.values():\n                        with torch.no_grad():\n                            if classification_amp:\n                                with torch.autocast(device_type='cuda', dtype=torch.float16):\n                                    outputs = model(inputs)\n                            else:\n                                outputs = model(inputs)\n\n                        outputs = outputs.cpu()\n                        if tta:\n                            outputs = torch.mean(outputs, dim=0)\n                        else:\n                            outputs = torch.squeeze(outputs, dim=0)\n\n                        crop_predictions[crop_idx] += outputs / len(models)\n\n            crop_predictions = torch.softmax(crop_predictions, dim=-1).numpy()\n            predictions.append(crop_predictions)\n            image_ids.append(np.array([image_id] * len(crop_predictions)))\n\n    predictions = np.concatenate(predictions)\n    image_ids = np.concatenate(image_ids)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:40.157581Z","iopub.execute_input":"2024-11-14T12:33:40.15806Z","iopub.status.idle":"2024-11-14T12:33:40.383366Z","shell.execute_reply.started":"2024-11-14T12:33:40.157996Z","shell.execute_reply":"2024-11-14T12:33:40.382016Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport torch\nimport torchvision.transforms as T\nfrom PIL import Image\n\n# Set device\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'\n\n# Define your classification model here (assuming it's already defined)\n# classification_model = ...  # Load your model\n\n# Define your classification crop size and number of top crops\nclassification_crop_size = 512  # Example crop size\nclassification_top_n_crops = 5   # Number of top crops to select\n\n# Placeholder for mask and image; these should be loaded or generated from your dataset\n# Example placeholders; replace these with actual data\nmask = np.zeros((2048, 3072), dtype=np.uint8)  # Replace with actual mask data\nimage = np.zeros((2048, 3072, 3), dtype=np.uint8)  # Replace with actual image data\n\n# Initialize empty lists for crops and image crops\ncrops = []\nimage_crops = []\n\n# Extract image dimensions\nimage_height, image_width = mask.shape\n\n# Define helper function to get maximum quotient for cropping\ndef get_max_quo(size, crop_size):\n    return (size + crop_size - 1) // crop_size\n\n# Get maximum quotients for height and width\nimage_height_max_quotient = get_max_quo(image_height, classification_crop_size)\nimage_width_max_quotient = get_max_quo(image_width, classification_crop_size)\n\n# Generate crops from mask\nfor h in range(image_height_max_quotient):\n    for w in range(image_width_max_quotient):\n        width_2 = min(image_width, (w + 1) * classification_crop_size)\n        height_2 = min(image_height, (h + 1) * classification_crop_size)\n        width_1 = width_2 - classification_crop_size\n        height_1 = height_2 - classification_crop_size\n        \n        # Crop the mask\n        mask_crop = mask[height_1:height_2, width_1:width_2]\n        area = np.sum(mask_crop) / 255.0  # Compute mask area\n        \n        # Append area and coordinates as a list of values\n        crops.append([area, width_1, height_1, width_2, height_2])  \n\n# Convert crops to a 2D numpy array\ncrops = np.array(crops)\n\n# Sort crops by mask area in descending order (crops[:, 0] refers to the first column, the area)\ncrops = crops[crops[:, 0].argsort()[::-1]].astype(np.int32)\n\nif len(crops) > 0:\n    print(f'{crops.shape[0]} crops are extracted from the mask')\n\n# Crop the raw image and store it\nfor crop_idx, crop in enumerate(crops[:classification_top_n_crops]):\n    area, width_1, height_1, width_2, height_2 = crop\n    # Store the cropped image\n    image_crop = image[height_1:height_2, width_1:width_2, :].copy()\n    image_crops.append(image_crop)\n    print(f'Crop {crop_idx}: Image Crop dimensions {image_crop.shape}')\n\n# Example transform for classification\nclassification_transforms = T.Compose([\n    T.ToPILImage(),\n    T.Resize((classification_crop_size, classification_crop_size)),\n    T.ToTensor(),\n])\n\n# Prepare crops for classification\nclassification_inputs = []\nfor image_crop in image_crops:\n    inputs = classification_transforms(image_crop)  # Corrected: Pass image_crop directly\n    inputs = inputs.unsqueeze(0).to(device)  # Add batch dimension and send to device\n    classification_inputs.append(inputs)\n\n# Placeholder for model prediction\n# with torch.no_grad():\n#     for inputs in classification_inputs:\n#         outputs = classification_model(inputs)  # Forward pass\n#         # Process outputs as needed...\n\nprint(\"Classification input preparation complete.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:48.856198Z","iopub.execute_input":"2024-11-14T12:33:48.857365Z","iopub.status.idle":"2024-11-14T12:33:48.916592Z","shell.execute_reply.started":"2024-11-14T12:33:48.857305Z","shell.execute_reply":"2024-11-14T12:33:48.915337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\n\n# Example image IDs (replace with actual data)\nimage_ids = ['41']  # List of image IDs\nnum_classes = 6  # Adjust based on your classification task\n\n# Example predictions (replace with actual model output)\n# Assuming you have 3 images and 6 classes\npredictions = np.random.rand(len(image_ids), num_classes)  # Random predictions for demonstration\n\n# Create DataFrame with image IDs\ndf_predictions = pd.DataFrame(data=image_ids, columns=['image_id'])\n\n# Label mapping\nlabel_mapping = {\n    0: 'HGSC',\n    1: 'EC',\n    2: 'CC',\n    3: 'LGSC',\n    4: 'MC',\n    5: 'Other',\n}\n\n# Adding predictions to the DataFrame\nfor label_idx, label in label_mapping.items():\n    df_predictions[f'{label}_prediction'] = predictions[:, label_idx]\n\n# Display the DataFrame\nprint(df_predictions)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:33:56.329349Z","iopub.execute_input":"2024-11-14T12:33:56.330408Z","iopub.status.idle":"2024-11-14T12:33:56.357495Z","shell.execute_reply.started":"2024-11-14T12:33:56.330341Z","shell.execute_reply":"2024-11-14T12:33:56.353458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torchvision.transforms as transforms\nimport cv2\nfrom PIL import Image\nimport numpy as np\n\n# Define your model architecture\nclass SomeClassificationModel(nn.Module):\n    def __init__(self):\n        super(SomeClassificationModel, self).__init__()\n        self.conv_layers = nn.Sequential(\n            nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1),  # Conv layer 1\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2),  # Pooling layer 1\n            nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),  # Conv layer 2\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2, stride=2)   # Pooling layer 2\n        )\n        \n        # Calculate the output size after the convolutional layers for a 224x224 input\n        self.flattened_size = 64 * (224 // 4) * (224 // 4)  # 64 channels, halved twice (2 pooling layers)\n        self.fc1 = nn.Linear(self.flattened_size, 256)  # First fully connected layer\n        self.fc2 = nn.Linear(256, 6)  # Output layer for classification\n\n    def forward(self, x):\n        x = self.conv_layers(x)\n        x = torch.flatten(x, 1)  # Flatten the tensor\n        x = self.fc1(x)\n        x = nn.ReLU()(x)\n        x = self.fc2(x)\n        return x\n\n# Define your classification transforms\nclassification_transforms = transforms.Compose([\n    transforms.Resize((224, 224)),  # Resize to expected input size\n    transforms.ToTensor(),            # Convert image to tensor\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Assuming a classification device is defined\nclassification_device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nmodel = SomeClassificationModel().to(classification_device)\n\npredictions = []\nimage_ids = []\n\n# Your processing loop\nfor idx, row in df.iterrows():\n    image_id = row['image_id']\n    image_path = row['image_path']\n    \n    # Read the image using OpenCV\n    image = cv2.imread(image_path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    \n    # Convert the image to a PIL Image for transformations\n    image_pil = Image.fromarray(image)\n    inputs = classification_transforms(image_pil)  # Apply transformations\n    \n    # Add a batch dimension\n    inputs = inputs.unsqueeze(0)  # Shape: [1, C, H, W]\n    \n    # Move inputs to the appropriate device\n    inputs = inputs.to(classification_device)\n    \n    # Debugging: print input shape\n    print(f'Input shape: {inputs.shape}')  # Should be [1, 3, 224, 224]\n    \n    # Forward pass\n    with torch.no_grad():\n        outputs = model(inputs)\n        \n    outputs = outputs.cpu()\n    predictions.append(outputs.numpy())\n    image_ids.append(np.array([image_id]))\n\n# Process predictions as needed\npredictions = np.concatenate(predictions)\nimage_ids = np.concatenate(image_ids)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:34:06.263126Z","iopub.execute_input":"2024-11-14T12:34:06.263571Z","iopub.status.idle":"2024-11-14T12:34:06.920044Z","shell.execute_reply.started":"2024-11-14T12:34:06.263527Z","shell.execute_reply":"2024-11-14T12:34:06.918325Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport cv2\nimport torch\nfrom PIL import Image\nimport imagesize\n\n# Assuming these functions are already defined:\n# drop_low_std, get_max_quo, visualize_image, read_image\n\npredictions = []\nimage_ids = []\n\nfor idx, row in df.iterrows():\n    \n    image_id = row['image_id']\n    image_type = row['image_type']\n    image_path = row['image_path']\n    \n    if image_type == 'tma':\n        image = cv2.imread(image_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        # Drop low standard deviation rows and columns (white areas with less tissue)\n        image = drop_low_std(image=image, threshold=10)\n        \n        tma_predictions = torch.zeros(1, 6)\n        \n        inputs = classification_transforms(image)  # Assuming classification_transforms works with RGB PIL Image\n        inputs = inputs.to(classification_device)\n\n        if tta:\n            inputs = torch.stack((\n                inputs,\n                torch.flip(inputs, dims=(1,)),\n                torch.flip(inputs, dims=(2,)),\n                torch.flip(inputs, dims=(1, 2))\n            ), dim=0)\n        else:\n            inputs = torch.unsqueeze(inputs, dim=0)\n\n        for model_idx, models in enumerate([models]):\n            for model in models.values():\n                with torch.no_grad():\n                    if classification_amp:\n                        with torch.autocast(device_type='cuda', dtype=torch.float16):\n                            outputs = model(inputs)\n                    else:\n                        outputs = model(inputs)\n\n                outputs = outputs.cpu()\n                if tta:\n                    outputs = torch.mean(outputs, dim=0)\n                else:\n                    outputs = torch.squeeze(outputs, dim=0)\n\n                tma_predictions += outputs / len(models)\n                \n        tma_predictions = torch.softmax(tma_predictions, dim=-1).numpy()\n        predictions.append(tma_predictions)\n        image_ids.append(np.array([image_id]))\n        \n    else:\n        image_thumbnail_path = str(competition_dataset / 'test_thumbnails' / f'{image_id}_thumbnail.png')\n        image_thumbnail = cv2.imread(image_thumbnail_path)\n        image_thumbnail = cv2.cvtColor(image_thumbnail, cv2.COLOR_BGR2RGB)\n        \n        if is_submission is False:\n            print(f'Image {image_id} {image_thumbnail.shape} thumbnail is loaded from {image_thumbnail_path}')\n            visualize_image(image=image_thumbnail, title=f'Image {image_id} Thumbnail {image_thumbnail.shape}', path='./thumbnail_raw.png')\n            \n        image_thumbnail_height, image_thumbnail_width = image_thumbnail.shape[:2]\n        thumbnail_height_padding = segmentation_size - image_thumbnail_height % segmentation_size\n        thumbnail_width_padding = segmentation_size - image_thumbnail_width % segmentation_size\n        image_thumbnail_padded = np.pad(image_thumbnail, ((0 + 64, thumbnail_height_padding + 64), (0 + 64, thumbnail_width_padding + 64), (0, 0)))\n        mask_padded = np.zeros((image_thumbnail_height + thumbnail_height_padding, image_thumbnail_width + thumbnail_width_padding), dtype=np.float32)\n        \n        if is_submission is False:\n            print(f'Image {image_id} {image_thumbnail_padded.shape} thumbnail and mask {mask_padded.shape} are padded')\n            visualize_image(image=image_thumbnail_padded, title=f'Image {image_id} Thumbnail Padded {image_thumbnail_padded.shape}', path='./thumbnail_padded.png')\n        \n        for height in range((image_thumbnail_height + thumbnail_height_padding) // segmentation_size):\n            height_1, height_2 = height * segmentation_size, (height + 1) * segmentation_size\n            for width in range((image_thumbnail_width + thumbnail_width_padding) // segmentation_size):\n                width_1, width_2 = width * segmentation_size, (width + 1) * segmentation_size\n                \n                image_thumbnail_tile = image_thumbnail_padded[height_1:height_2 + 128, width_1:width_2 + 128]\n                inputs = segmentation_transforms(image=image_thumbnail_tile)['image'].to(segmentation_device)\n                inputs = inputs.float()  # Ensure inputs are float\n                \n                inputs = torch.stack((\n                    inputs,\n                    torch.flip(inputs, dims=(1,)),\n                    torch.flip(inputs, dims=(2,)),\n                    torch.flip(inputs, dims=(1, 2))\n                ), dim=0)\n                \n                with torch.no_grad():\n                    if segmentation_amp:\n                        with torch.autocast(device_type='cuda', dtype=torch.float16):\n                            outputs = segmentation_model(inputs)\n                    else:\n                        outputs = segmentation_model(inputs)\n                    \n                outputs = outputs.cpu()\n                outputs = torch.stack((\n                    outputs[0],\n                    torch.flip(outputs[1], dims=(1,)),\n                    torch.flip(outputs[2], dims=(2,)),\n                    torch.flip(outputs[3], dims=(1, 2)),\n                ), dim=0)\n                outputs = torch.mean(outputs, dim=0).squeeze().cpu().numpy()\n                \n                # Resize outputs to match the expected size in mask_padded\n                outputs_resized = cv2.resize(outputs, (width_2 - width_1, height_2 - height_1), interpolation=cv2.INTER_NEAREST)\n                mask_padded[height_1:height_2, width_1:width_2] = outputs_resized\n                \n                if is_submission is False:\n                    print(f'Predicted x ({width_1}-{width_2}) y ({height_1}-{height_2})')\n                        \n        mask = mask_padded[:image_thumbnail_height, :image_thumbnail_width]\n        del mask_padded\n        \n        if is_submission is False:\n            print(f'Image {image_id} {mask.shape} mask is predicted')\n            visualize_image(image=image_thumbnail, title=f'Image {image_id} Thumbnail and Mask {mask.shape}', mask=mask, path='./thumbnail_mask.png')\n            \n        # Extract image size from the image headers\n        image_width, image_height = imagesize.get(image_path)\n        # Cast mask soft predictions to 8-bit integer and upsample\n        mask = np.uint8(mask * 255)\n        mask = cv2.resize(mask, (image_width, image_height), interpolation=cv2.INTER_NEAREST)\n        \n        predictions.append(mask)\n        image_ids.append(np.array([image_id]))\n\n# Process predictions as needed\npredictions = np.concatenate(predictions)\nimage_ids = np.concatenate(image_ids)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:34:18.661584Z","iopub.execute_input":"2024-11-14T12:34:18.662178Z","iopub.status.idle":"2024-11-14T12:34:18.816852Z","shell.execute_reply.started":"2024-11-14T12:34:18.662132Z","shell.execute_reply":"2024-11-14T12:34:18.815214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport torch\nimport torchvision.transforms as transforms\nimport cv2\nfrom PIL import Image\n\n# Assuming your model and other configurations are defined\n\n# Define your classification transforms\nclassification_transforms = transforms.Compose([\n    transforms.Resize((224, 224)),  # Resize to expected input size\n    transforms.ToTensor(),            # Convert image to tensor\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# Example DataFrame df containing 'image_id' and 'image_path'\n# df = pd.DataFrame({\n#     'image_id': ['img1', 'img2', 'img3', ...],\n#     'image_path': ['path/to/img1.jpg', 'path/to/img2.jpg', 'path/to/img3.jpg', ...]\n# })\n\npredictions = []  # Initialize predictions list\nimage_ids = []    # Initialize image_ids list\n\n# Your processing loop\nfor idx, row in df.iterrows():\n    image_id = row['image_id']\n    image_path = row['image_path']\n    \n    # Read the image using OpenCV\n    image = cv2.imread(image_path)\n    image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n    \n    # Convert the image to a PIL Image for transformations\n    image_pil = Image.fromarray(image)\n    inputs = classification_transforms(image_pil)  # Apply transformations\n    \n    # Add a batch dimension\n    inputs = inputs.unsqueeze(0)  # Shape: [1, C, H, W]\n    \n    # Move inputs to the appropriate device (assumed 'classification_device' is defined)\n    inputs = inputs.to(classification_device)\n    \n    # Debugging: print input shape\n    print(f'Input shape: {inputs.shape}')  # Should be [1, 3, 224, 224]\n    \n    # Forward pass\n    with torch.no_grad():\n        outputs = model(inputs)\n        \n    outputs = outputs.cpu().numpy()  # Move outputs to CPU and convert to numpy\n    predictions.append(outputs)        # Append to predictions\n    image_ids.append(image_id)         # Append the image ID\n\n# Convert predictions and image_ids to numpy arrays\npredictions = np.vstack(predictions)  # Stack predictions\nimage_ids = np.array(image_ids)        # Convert to numpy array\n\n# Check shapes for debugging\nprint(\"Shape of predictions:\", predictions.shape)  # Should be (num_images, num_classes)\nprint(\"Shape of image_ids:\", image_ids.shape)      # Should be (num_images,)\n\n# Create DataFrame for predictions\ndf_predictions = pd.DataFrame(data={\"image_id\": image_ids})\n\n# Define label mapping\nlabel_mapping = {\n    0: 'HGSC',\n    1: 'EC',\n    2: 'CC',\n    3: 'LGSC',\n    4: 'MC',\n    5: 'Other',\n}\n\n# Add predictions to the DataFrame\nfor label_idx, label in label_mapping.items():\n    if predictions.shape[0] != df_predictions.shape[0]:\n        raise ValueError(f\"Shape mismatch: predictions ({predictions.shape[0]}) \"\n                         f\"and df_predictions ({df_predictions.shape[0]})\")\n    \n    df_predictions[f'{label}_prediction'] = predictions[:, label_idx]\n\n# Display the resulting DataFrame\nprint(df_predictions)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:34:24.641204Z","iopub.execute_input":"2024-11-14T12:34:24.641652Z","iopub.status.idle":"2024-11-14T12:34:24.716761Z","shell.execute_reply.started":"2024-11-14T12:34:24.641609Z","shell.execute_reply":"2024-11-14T12:34:24.715217Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"prediction_columns = [f'{label}_prediction' for label in list(label_mapping.values())]\n\ndf_predictions = df_predictions.groupby('image_id')[prediction_columns].mean().reset_index()\ndf_predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:34:30.837986Z","iopub.execute_input":"2024-11-14T12:34:30.838481Z","iopub.status.idle":"2024-11-14T12:34:30.872817Z","shell.execute_reply.started":"2024-11-14T12:34:30.838436Z","shell.execute_reply":"2024-11-14T12:34:30.871721Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_predictions['label'] = np.argmax(df_predictions[prediction_columns], axis=-1)\ndf_predictions['label'] = df_predictions['label'].map(label_mapping)\n\ndf_predictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:34:38.311288Z","iopub.execute_input":"2024-11-14T12:34:38.311766Z","iopub.status.idle":"2024-11-14T12:34:38.334052Z","shell.execute_reply.started":"2024-11-14T12:34:38.311722Z","shell.execute_reply":"2024-11-14T12:34:38.332707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_submission = pd.read_csv(competition_dataset / 'sample_submission.csv').drop(columns=['label'])\ndf_submission","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-14T12:34:46.503613Z","iopub.execute_input":"2024-11-14T12:34:46.504179Z","iopub.status.idle":"2024-11-14T12:34:46.522317Z","shell.execute_reply.started":"2024-11-14T12:34:46.504128Z","shell.execute_reply":"2024-11-14T12:34:46.520796Z"}},"outputs":[],"execution_count":null}]}