{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":39272,"databundleVersionId":4629629,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"! pip install -qU \"python-gdcm\" pydicom pylibjpeg \"opencv-python-headless\" \"scikit-image\" \"ipywidgets\" \"dicomsdl\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:28:01.131127Z","iopub.execute_input":"2025-05-17T07:28:01.131373Z","iopub.status.idle":"2025-05-17T07:28:07.411804Z","shell.execute_reply.started":"2025-05-17T07:28:01.131355Z","shell.execute_reply":"2025-05-17T07:28:07.411116Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 1. Handle datasets\nimport io\nimport os\nimport cv2\nimport imageio\nimport pydicom\nimport dicomsdl\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nfrom glob import glob\nimport tifffile as tiff\nimport SimpleITK as sitk\nfrom pathlib import Path\nfrom tqdm.auto import tqdm\nimport multiprocessing as mp\nfrom collections import Counter\nfrom joblib import Parallel, delayed\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:28:09.024773Z","iopub.execute_input":"2025-05-17T07:28:09.025372Z","iopub.status.idle":"2025-05-17T07:28:11.357274Z","shell.execute_reply.started":"2025-05-17T07:28:09.02534Z","shell.execute_reply":"2025-05-17T07:28:11.356705Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"RESIZE_TO = 512\nSAVE_DIR = f\"/kaggle/working/train_image_processed_jp2000_{RESIZE_TO}\"\nparent_dir = \"/kaggle/input/rsna-breast-cancer-detection\"\n\n# create the top-level folder\nos.makedirs(SAVE_DIR, exist_ok=True)\n\n# Gather all .dcm paths\nall_dcm_files = list(Path(os.path.join(parent_dir, \"train_images\")).rglob(\"*.dcm\"))\nfail_counter = Counter()\n\ndef image_resize(image, width = None, height = None, inter = cv2.INTER_LINEAR):\n    \n    dim = None\n    (h, w) = image.shape[:2]\n    \n    if width is None and height is None:\n        return image\n\n    if width is None:\n        r = height / float(h)\n        dim = (int(w * r), height)\n    else:\n        r = width / float(w)\n        dim = (width, int(h * r))\n    \n    resized = cv2.resize(image, dim, interpolation=inter)\n    return resized\n\ndef apply_window(image, window_center, window_width):\n    img = image.copy().astype(np.float32)\n    min_val = window_center - window_width / 2\n    max_val = window_center + window_width / 2\n    img = np.clip(img, min_val, max_val)\n    img = (img - min_val) / (max_val - min_val)\n    return img\n\ndef dicom_file_to_array(path):\n    dicom = dicomsdl.open(str(path))\n    data = dicom.pixelData().astype(np.float32)\n    photometric = dicom.getPixelDataInfo()['PhotometricInterpretation']  # Cache this once\n    \n    if photometric == \"MONOCHROME1\":\n        data = data.max() - data\n    \n    # ===== Windowing =====\n    try:\n        center = dicom.getMeta(\"0028|1050\")  # Window Center\n        width = dicom.getMeta(\"0028|1051\")   # Window Width\n        \n        if isinstance(center, list):\n            center = float(center[0])\n        else:\n            center = float(center)\n        \n        if isinstance(width, list):\n            width = float(width[0])\n        else:\n            width = float(width)\n        \n        data = apply_window(data, center, width)\n        \n    except Exception:\n        # Fall back to default normalization if window info is missing\n        data = (data - data.min()) / (data.max() - data.min())\n\n    # Resize    \n    h, w = data.shape\n    if w > h:\n        data = image_resize(data, width=RESIZE_TO)\n    else:\n        data = image_resize(data, height=RESIZE_TO)\n    \n    return (data * 255).astype(np.uint8)\n\ndef process(path):\n    try:\n        parent_folder = path.parent.name\n        save_subdir = os.path.join(parent_dir, SAVE_DIR, parent_folder)\n        os.makedirs(save_subdir, exist_ok=True)\n\n        processed_img = dicom_file_to_array(path)\n        save_path = os.path.join(save_subdir, f\"{path.stem}.jp2\")\n        imageio.imwrite(save_path, processed_img, format='JP2')\n\n    except Exception as e:\n        print(f\"[ERROR] Failed: {path} — {e}\")\n        fail_counter[\"fail\"] += 1\n\n# Process with tqdm and joblib\nParallel(n_jobs=16, backend=\"loky\", prefer=\"threads\")(\n    delayed(process)(path) for path in tqdm(all_dcm_files, \n                                            total=len(all_dcm_files))\n)\n\nprint(f\"✅ Done! Processed {len(all_dcm_files)} images.\")\nprint(f\"❌ Failed: {fail_counter['fail']}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T07:28:15.466087Z","iopub.execute_input":"2025-05-17T07:28:15.466726Z","iopub.status.idle":"2025-05-17T11:11:55.572433Z","shell.execute_reply.started":"2025-05-17T07:28:15.4667Z","shell.execute_reply":"2025-05-17T11:11:55.571618Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def open_jpeg2000_image(image_path):\n    # Read the JPEG2000 image using OpenCV\n    img = plt.imread(image_path)\n    \n    plt.imshow(img, cmap=\"turbo\")\n    plt.axis('off')\n    plt.show()\n\n# Example usage\nimage_path = os.path.join(SAVE_DIR, \"105\", \"397491913.jp2\")\nif os.path.exists(image_path):\n    open_jpeg2000_image(image_path)\nelse:\n    print(\"False\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T18:02:58.779294Z","iopub.execute_input":"2025-05-16T18:02:58.780026Z","iopub.status.idle":"2025-05-16T18:02:58.789855Z","shell.execute_reply.started":"2025-05-16T18:02:58.779999Z","shell.execute_reply":"2025-05-16T18:02:58.788884Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# zip up your processed JP2 folder\n!zip -r /kaggle/working/processed_jp2.zip /kaggle/working/train_image_processed_jp2000_512\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-17T11:55:09.388298Z","iopub.execute_input":"2025-05-17T11:55:09.388591Z"}},"outputs":[],"execution_count":null}]}