{"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":20604,"databundleVersionId":1357052,"sourceType":"competition"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install torch torchvision","metadata":{"execution":{"iopub.status.busy":"2024-10-23T19:19:18.318186Z","iopub.execute_input":"2024-10-23T19:19:18.318686Z","iopub.status.idle":"2024-10-23T19:19:34.064439Z","shell.execute_reply.started":"2024-10-23T19:19:18.318638Z","shell.execute_reply":"2024-10-23T19:19:34.063005Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn","metadata":{"execution":{"iopub.status.busy":"2024-10-24T01:20:12.586619Z","iopub.execute_input":"2024-10-24T01:20:12.587051Z","iopub.status.idle":"2024-10-24T01:20:15.684599Z","shell.execute_reply.started":"2024-10-24T01:20:12.58701Z","shell.execute_reply":"2024-10-24T01:20:15.683427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass ResnetBlock(nn.Module):\n    def __init__(self, dim):\n        super(ResnetBlock, self).__init__()\n        self.conv_block = self.build_conv_block(dim)\n\n    def build_conv_block(self, dim):\n        conv_block = [nn.Conv2d(dim, dim, kernel_size=3, padding=1),\n                      nn.InstanceNorm2d(dim),\n                      nn.ReLU(True)]\n\n        conv_block += [nn.Conv2d(dim, dim, kernel_size=3, padding=1),\n                       nn.InstanceNorm2d(dim)]\n        return nn.Sequential(*conv_block)\n\n    def forward(self, x):\n        return x + self.conv_block(x)\n\nclass GeneratorResNet(nn.Module):\n    def __init__(self, input_nc, output_nc, n_residual_blocks=9):\n        super(GeneratorResNet, self).__init__()\n\n        # Initial convolution block\n        model = [nn.Conv2d(input_nc, 64, kernel_size=7, padding=3),\n                 nn.InstanceNorm2d(64),\n                 nn.ReLU(inplace=True)]\n\n        # Downsampling\n        in_features = 64\n        out_features = in_features * 2\n        for _ in range(2):\n            model += [nn.Conv2d(in_features, out_features, kernel_size=3, stride=2, padding=1),\n                      nn.InstanceNorm2d(out_features),\n                      nn.ReLU(inplace=True)]\n            in_features = out_features\n            out_features = in_features * 2\n\n        # Residual blocks\n        for _ in range(n_residual_blocks):\n            model += [ResnetBlock(in_features)]\n\n        # Upsampling\n        out_features = in_features // 2\n        for _ in range(2):\n            model += [nn.ConvTranspose2d(in_features, out_features, kernel_size=3, stride=2, padding=1, output_padding=1),\n                      nn.InstanceNorm2d(out_features),\n                      nn.ReLU(inplace=True)]\n            in_features = out_features\n            out_features = in_features // 2\n\n        # Output layer\n        model += [nn.Conv2d(64, output_nc, kernel_size=7, padding=3),\n                  nn.Tanh()]\n\n        self.model = nn.Sequential(*model)\n\n    def forward(self, x):\n        return self.model(x)\n\nclass Discriminator(nn.Module):\n    def __init__(self, input_nc):\n        super(Discriminator, self).__init__()\n\n        model = [nn.Conv2d(input_nc, 64, kernel_size=4, stride=2, padding=1),\n                 nn.LeakyReLU(0.2, inplace=True)]\n\n        model += [nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1),\n                  nn.InstanceNorm2d(128),\n                  nn.LeakyReLU(0.2, inplace=True)]\n\n        model += [nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1),\n                  nn.InstanceNorm2d(256),\n                  nn.LeakyReLU(0.2, inplace=True)]\n\n        model += [nn.Conv2d(256, 512, kernel_size=4, stride=1, padding=1),\n                  nn.InstanceNorm2d(512),\n                  nn.LeakyReLU(0.2, inplace=True)]\n\n        model += [nn.Conv2d(512, 1, kernel_size=4, stride=1, padding=1)]\n\n        self.model = nn.Sequential(*model)\n\n    def forward(self, x):\n        return self.model(x)","metadata":{"execution":{"iopub.status.busy":"2024-10-24T01:20:57.940187Z","iopub.execute_input":"2024-10-24T01:20:57.940983Z","iopub.status.idle":"2024-10-24T01:20:57.965385Z","shell.execute_reply.started":"2024-10-24T01:20:57.940932Z","shell.execute_reply":"2024-10-24T01:20:57.964139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the device to use (GPU if available)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n# Ensure all models are moved to the same device\ngenerator_G = generator_G.to(device)\ngenerator_F = generator_F.to(device)\ndiscriminator_X = discriminator_X.to(device)\ndiscriminator_Y = discriminator_Y.to(device)\n","metadata":{"execution":{"iopub.status.busy":"2024-10-24T01:21:15.614008Z","iopub.execute_input":"2024-10-24T01:21:15.614679Z","iopub.status.idle":"2024-10-24T01:21:15.634264Z","shell.execute_reply.started":"2024-10-24T01:21:15.61462Z","shell.execute_reply":"2024-10-24T01:21:15.632833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import itertools\nimport torch.optim as optim\n\n# Initialize models\ninput_nc = 1  # Single channel (CT scans)\noutput_nc = 1  # Output single channel (MRI-like simulated)\ngenerator_G = GeneratorResNet(input_nc, output_nc)  # CT -> MRI-like (simulated)\ngenerator_F = GeneratorResNet(input_nc, output_nc)  # MRI-like -> CT\ndiscriminator_X = Discriminator(input_nc)  # CT discriminator\ndiscriminator_Y = Discriminator(input_nc)  # MRI-like discriminator\n\n# Loss functions\ncriterion_GAN = nn.MSELoss()  # GAN loss\ncriterion_cycle = nn.L1Loss()  # Cycle-consistency loss\n\n# Optimizers\nlr = 0.0002\noptimizer_G = optim.Adam(itertools.chain(generator_G.parameters(), generator_F.parameters()), lr=lr, betas=(0.5, 0.999))\noptimizer_D_X = optim.Adam(discriminator_X.parameters(), lr=lr, betas=(0.5, 0.999))\noptimizer_D_Y = optim.Adam(discriminator_Y.parameters(), lr=lr, betas=(0.5, 0.999))\n\n# Training loop for unpaired CT data\ndef train_cycle_gan_unpaired_ct(num_epochs, dataloader):\n    for epoch in range(num_epochs):\n        for i, data in enumerate(dataloader):\n            # Move real CT images to the same device\n            real_CT = data['CT'].to(device)\n\n            # Forward pass through generators\n            optimizer_G.zero_grad()\n\n            fake_MRI = generator_G(real_CT)\n            recovered_CT = generator_F(fake_MRI)\n\n            # GAN loss\n            pred_fake = discriminator_Y(fake_MRI)\n            loss_GAN_G = criterion_GAN(pred_fake, torch.ones_like(pred_fake))\n\n            pred_real = discriminator_X(real_CT)\n            loss_GAN_F = criterion_GAN(pred_real, torch.ones_like(pred_real))\n\n            # Cycle-consistency loss\n            loss_cycle = criterion_cycle(recovered_CT, real_CT)\n\n            # Total generator loss\n            loss_G = loss_GAN_G + loss_GAN_F + 10 * loss_cycle\n            loss_G.backward()\n            optimizer_G.step()\n\n            # Update discriminators\n            optimizer_D_X.zero_grad()\n            optimizer_D_Y.zero_grad()\n\n            pred_real = discriminator_X(real_CT)\n            loss_D_real_X = criterion_GAN(pred_real, torch.ones_like(pred_real))\n\n            pred_fake = discriminator_X(recovered_CT.detach())\n            loss_D_fake_X = criterion_GAN(pred_fake, torch.zeros_like(pred_fake))\n            loss_D_X = (loss_D_real_X + loss_D_fake_X) * 0.5\n            loss_D_X.backward()\n            optimizer_D_X.step()\n\n            if i % 100 == 0:\n                print(f\"Epoch {epoch}/{num_epochs}, Step {i}, Generator Loss: {loss_G.item()}, Discriminator X Loss: {loss_D_X.item()}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-24T01:21:11.750828Z","iopub.execute_input":"2024-10-24T01:21:11.751271Z","iopub.status.idle":"2024-10-24T01:21:12.155955Z","shell.execute_reply.started":"2024-10-24T01:21:11.75123Z","shell.execute_reply":"2024-10-24T01:21:12.154785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport pydicom\nfrom PIL import Image\nimport numpy as np\nfrom torch.utils.data import Dataset\n\nclass CustomMedicalDataset(Dataset):\n    def __init__(self, root_dir, transform=None):\n        self.root_dir = root_dir\n        self.transform = transform\n        self.image_filenames = [f for f in os.listdir(root_dir) if f.endswith('.dcm')]\n\n    def __len__(self):\n        return len(self.image_filenames)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.root_dir, self.image_filenames[idx])\n        \n        # Load the DICOM file\n        dicom_image = pydicom.dcmread(img_name)\n        image = dicom_image.pixel_array  # Get image array\n        \n        # Convert the DICOM array to a PIL image\n        image = Image.fromarray(image).convert('RGB')  # Convert to RGB format\n\n        if self.transform:\n            image = self.transform(image)\n\n        sample = {'CT': image}\n        return sample\n","metadata":{"execution":{"iopub.status.busy":"2024-10-24T01:21:23.203706Z","iopub.execute_input":"2024-10-24T01:21:23.204199Z","iopub.status.idle":"2024-10-24T01:21:23.2146Z","shell.execute_reply.started":"2024-10-24T01:21:23.204157Z","shell.execute_reply":"2024-10-24T01:21:23.213489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nprint(os.listdir(\"/kaggle/input/osic-pulmonary-fibrosis-progression/test/ID00419637202311204720264\"))\n","metadata":{"execution":{"iopub.status.busy":"2024-10-23T19:22:11.654277Z","iopub.execute_input":"2024-10-23T19:22:11.654745Z","iopub.status.idle":"2024-10-23T19:22:11.661724Z","shell.execute_reply.started":"2024-10-23T19:22:11.6547Z","shell.execute_reply":"2024-10-23T19:22:11.660643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from torch.utils.data import DataLoader\nfrom torchvision import transforms\n\n# Apply transformations to resize images and convert to Tensor\n# Modify the transform to include grayscale conversion\ntransform = transforms.Compose([\n    transforms.Grayscale(num_output_channels=1),  # Convert to grayscale with 1 channel\n    transforms.Resize((256, 256)),\n    transforms.ToTensor()\n])\n\n# Now, initialize the dataset and dataloader with the modified transform\nct_dataset = CustomMedicalDataset(root_dir=\"/kaggle/input/osic-pulmonary-fibrosis-progression/test/ID00419637202311204720264\", transform=transform)\ndataloader = DataLoader(ct_dataset, batch_size=1, shuffle=True)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-24T01:21:28.499405Z","iopub.execute_input":"2024-10-24T01:21:28.500196Z","iopub.status.idle":"2024-10-24T01:21:28.51574Z","shell.execute_reply.started":"2024-10-24T01:21:28.500147Z","shell.execute_reply":"2024-10-24T01:21:28.514563Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_cycle_gan_unpaired_ct(num_epochs=200, dataloader=dataloader)","metadata":{"execution":{"iopub.status.busy":"2024-10-24T02:23:22.31498Z","iopub.execute_input":"2024-10-24T02:23:22.315422Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.save(generator_G.state_dict(), \"generator_CT_to_MRI.pth\")\ntorch.save(generator_F.state_dict(), \"generator_MRI_to_CT.pth\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nfrom pydicom.dataset import Dataset, FileDataset\nfrom datetime import datetime\nimport tempfile\nimport torch\nfrom torchvision import transforms\nimport numpy as np\nfrom PIL import Image","metadata":{"execution":{"iopub.status.busy":"2024-10-24T01:20:46.476Z","iopub.execute_input":"2024-10-24T01:20:46.476488Z","iopub.status.idle":"2024-10-24T01:20:48.427934Z","shell.execute_reply.started":"2024-10-24T01:20:46.476432Z","shell.execute_reply":"2024-10-24T01:20:48.426771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load the CT-to-MRI generator model (CycleGAN generator)\ngenerator_CT_to_MRI = GeneratorResNet(input_nc=1, output_nc=1)  # Input CT image (grayscale), output MRI-like (grayscale)\ngenerator_CT_to_MRI.load_state_dict(torch.load('generator_CT_to_MRI.pth'))\ngenerator_CT_to_MRI.eval()  # Set the model to evaluation mode\ngenerator_CT_to_MRI = generator_CT_to_MRI.to(device)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\n\n# Read DICOM file with a default Transfer Syntax if missing\ndef read_dicom_file(file_path):\n    dicom_data = pydicom.dcmread(file_path)\n\n    # If the Transfer Syntax UID is missing, set it to Implicit VR Little Endian\n    if 'TransferSyntaxUID' not in dicom_data.file_meta:\n        dicom_data.file_meta.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian\n\n    return dicom_data","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport pydicom\nfrom pydicom.dataset import FileMetaDataset, FileDataset\nfrom datetime import datetime\n\n# Function to generate MRI-like image from CT and save as JPEG\ndef generate_mri_like_from_ct(ct_dicom_path):\n    # Load the DICOM file using pydicom\n    dicom_data = pydicom.dcmread(ct_dicom_path)\n    \n    # Extract the pixel data (this will be a NumPy array)\n    ct_image_array = dicom_data.pixel_array\n    \n    # Normalize pixel values to range [-1, 1] (assuming 16-bit data)\n    ct_image_array = ct_image_array.astype(np.float32)\n    ct_image_array = (ct_image_array / np.max(ct_image_array)) * 2.0 - 1.0\n\n    # Convert the NumPy array to a PIL image for resizing\n    pil_image = Image.fromarray(ct_image_array)\n\n    # Resize the image to the size expected by the model (e.g., 256x256)\n    pil_image = pil_image.resize((256, 256))\n\n    # Convert the resized image back to a NumPy array\n    ct_image_array_resized = np.array(pil_image)\n\n    # Add the required batch and channel dimensions for model input: (1, 256, 256, 1)\n    ct_image_tensor = torch.tensor(ct_image_array_resized).unsqueeze(0).unsqueeze(0).to(device)\n\n    # Generate the MRI-like image from the CT image using the CycleGAN generator\n    with torch.no_grad():\n        mri_like_image = generator_CT_to_MRI(ct_image_tensor)\n\n    # Convert back to an image (from Tensor to PIL Image)\n    mri_like_image = mri_like_image.squeeze(0).cpu().detach()\n    mri_like_pil = transforms.ToPILImage()(mri_like_image)\n\n    # Save the MRI-like image as a JPEG file\n    jpeg_file_path = os.path.join(\"/kaggle/working/\", \"generated_mri_like_image.jpg\")\n    mri_like_pil.save(jpeg_file_path, \"JPEG\")\n\n    return jpeg_file_path","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Path to the CT DICOM file\nct_dicom_path = '/kaggle/input/osic-pulmonary-fibrosis-progression/test/ID00419637202311204720264/1.dcm'\n\n# Generate the MRI-like image and save it as a JPEG\njpeg_file_path = generate_mri_like_from_ct(ct_dicom_path)\n\n# Output the location of the generated JPEG file\nprint(f\"MRI-like image saved as JPEG at: {jpeg_file_path}\")\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\n\n# Read DICOM file with a default Transfer Syntax if missing\ndef read_dicom_file(file_path):\n    dicom_data = pydicom.dcmread(file_path)\n\n    # If the Transfer Syntax UID is missing, set it to Implicit VR Little Endian\n    if 'TransferSyntaxUID' not in dicom_data.file_meta:\n        dicom_data.file_meta.TransferSyntaxUID = pydicom.uid.ImplicitVRLittleEndian\n\n    # Print important header values for debugging\n    print(f\"Rows: {dicom_data.Rows}\")\n    print(f\"Columns: {dicom_data.Columns}\")\n    print(f\"Bits Allocated: {dicom_data.BitsAllocated}\")\n    print(f\"Pixel Data Length: {len(dicom_data.PixelData)}\")\n    print(f\"Expected Pixel Data Size: {dicom_data.Rows * dicom_data.Columns * (dicom_data.BitsAllocated // 8)} bytes\")\n    print(f\"Transfer Syntax UID: {dicom_data.file_meta.TransferSyntaxUID}\")\n\n    return dicom_data\n","metadata":{"execution":{"iopub.status.busy":"2024-10-24T02:19:48.675715Z","iopub.execute_input":"2024-10-24T02:19:48.676141Z","iopub.status.idle":"2024-10-24T02:19:48.684702Z","shell.execute_reply.started":"2024-10-24T02:19:48.676103Z","shell.execute_reply":"2024-10-24T02:19:48.68318Z"},"trusted":true},"execution_count":null,"outputs":[]}]}