{
  "id": 527759,
  "title": "Breaking down 2d slices of Axial Images into their respective levels",
  "url": "/competitions/rsna-2024-lumbar-spine-degenerative-classification/discussion/527759",
  "author_name": "",
  "post_date": "2024-08-13T15:50:23.010282800Z",
  "votes": 12,
  "comment_count": 1,
  "views": 0,
  "content": "<p>`import os<br>\nimport numpy as np<br>\nimport pydicom<br>\nimport matplotlib.pyplot as plt<br>\nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection<br>\nfrom sklearn.cluster import KMeans</p>\n<h1>Function to load DICOM files and extract IOP and positions</h1>\n<p>def load_dicom_slices(directory):<br>\n    slices = []<br>\n    filepaths = []<br>\n    for filename in os.listdir(directory):<br>\n        if filename.endswith(\".dcm\"):<br>\n            filepath = os.path.join(directory, filename)<br>\n            ds = pydicom.dcmread(filepath)<br>\n            slices.append(ds)<br>\n            filepaths.append(filepath)<br>\n    return slices, filepaths</p>\n<p>def extract_iop_and_position(slices):<br>\n    iop_vectors = []<br>\n    positions = []<br>\n    for slice in slices:<br>\n        iop = np.array(slice.ImageOrientationPatient).reshape(2, 3)<br>\n        iop_normal = np.cross(iop[0], iop[1])  # Calculate normal vector<br>\n        position = np.array(slice.ImagePositionPatient)<br>\n        iop_vectors.append(iop_normal)<br>\n        positions.append(position)<br>\n    return np.array(iop_vectors), np.array(positions)</p>\n<p>def cluster_slices_by_iop(iop_vectors, n_clusters=5):<br>\n    kmeans = KMeans(n_clusters=n_clusters)<br>\n    labels = kmeans.fit_predict(iop_vectors)<br>\n    return labels</p>\n<p>def sort_slices_within_clusters(labels, positions, filepaths):<br>\n    sorted_slices = {}<br>\n    for cluster_label in np.unique(labels):<br>\n        cluster_indices = np.where(labels == cluster_label)[0]<br>\n        cluster_positions = positions[cluster_indices]<br>\n        # Sort based on the z-component of the position vector<br>\n        sorted_indices = np.argsort(cluster_positions[:, 2])<br>\n        sorted_slices[cluster_label] = [filepaths[idx] for idx in cluster_indices[sorted_indices]]<br>\n    return sorted_slices</p>\n<p>def print_cluster_file_paths(sorted_slices):<br>\n    for cluster_label, filepaths in sorted_slices.items():<br>\n        print(f\"Cluster {cluster_label}:\")<br>\n        for filepath in filepaths:<br>\n            print(f\"    {filepath}\")</p>\n<p>def plot_clusters(slices, labels, positions, sorted_slices):<br>\n    fig = plt.figure(figsize=(12, 6))</p>\n<pre><code>\nax1 = fig.add_subplot(121, =)\nax2 = fig.add_subplot(122, =)\n\n\ncolors = plt.cm.rainbow(np.linspace(0, 1, len(sorted_slices)))\n\n cluster_label, color  zip(sorted_slices.keys(), colors):\n     idx  range(len(sorted_slices[cluster_label])):\n        #  the DICOM slice  this index\n        filepath = sorted_slices[cluster_label][idx]\n        ds = pydicom.dcmread(filepath)\n\n        #  the 3 points that define the plane (corner points of the slice)\n        iop = np.array(ds.ImageOrientationPatient).reshape(2, 3)\n        ipp = np.array(ds.ImagePositionPatient)\n        row_dir = iop[0] * ds.Rows\n        col_dir = iop[1] * ds.Columns\n\n        p1 = ipp\n        p2 = ipp + row_dir\n        p3 = ipp + col_dir\n\n        # Plane defined by three points\n        vertices = [p1, p2, p2 + col_dir, p3]\n\n        # Create a new Poly3DCollection  each axis\n        plane1 = Poly3DCollection([vertices], =color, =0.3)\n        plane2 = Poly3DCollection([vertices], =color, =0.3)\n\n        ax1.add_collection3d(plane1)\n        ax2.add_collection3d(plane2)\n\n        # Plot the points\n        ax1.scatter(*p1, =)\n        ax2.scatter(*p1, =)\n\n\nax1.set_xlabel()\nax1.set_ylabel()\nax1.set_zlabel()\n\nax2.set_xlabel()\nax2.set_ylabel()\nax2.set_zlabel()\n\n\nax1.set_box_aspect([1, 1, 1])\nax2.set_box_aspect([1, 1, 1])\n\nplt.show()\n</code></pre>\n<h1>Main function to process the DICOM slices and visualize them</h1>\n<p>def process_and_plot_dicom_slices(directory, n_clusters=5):<br>\n    slices, filepaths = load_dicom_slices(directory)<br>\n    iop_vectors, positions = extract_iop_and_position(slices)<br>\n    labels = cluster_slices_by_iop(iop_vectors, n_clusters)<br>\n    sorted_slices = sort_slices_within_clusters(labels, positions, filepaths)<br>\n    print_cluster_file_paths(sorted_slices)  # Print file paths for each cluster<br>\n    plot_clusters(slices, labels, positions, sorted_slices)</p>\n<h1>Example usage</h1>\n<p>dicom_directory = \"rsna_clipped/1008446160/3775545364\"<br>\nprocess_and_plot_dicom_slices(dicom_directory, n_clusters=5)<br>\n`<br>\nThis code outputs the images grouped by their respective levels, organized into clusters. The rest of the process is straightforward.</p>\n<p><em>Cluster 0:\n    rsna_clipped/1008446160/3775545364\\13.dcm\n    rsna_clipped/1008446160/3775545364\\12.dcm\n    rsna_clipped/1008446160/3775545364\\11.dcm\n    rsna_clipped/1008446160/3775545364\\10.dcm\n    rsna_clipped/1008446160/3775545364\\9.dcm\nCluster 1:\n    rsna_clipped/1008446160/3775545364\\24.dcm\n    rsna_clipped/1008446160/3775545364\\23.dcm\n    rsna_clipped/1008446160/3775545364\\22.dcm\n    rsna_clipped/1008446160/3775545364\\21.dcm\n    rsna_clipped/1008446160/3775545364\\20.dcm\n    rsna_clipped/1008446160/3775545364\\19.dcm\nCluster 2:\n    rsna_clipped/1008446160/3775545364\\18.dcm\n    rsna_clipped/1008446160/3775545364\\17.dcm\n    rsna_clipped/1008446160/3775545364\\16.dcm\n    rsna_clipped/1008446160/3775545364\\15.dcm\n    rsna_clipped/1008446160/3775545364\\14.dcm\nCluster 3:\n    rsna_clipped/1008446160/3775545364\\4.dcm\n    rsna_clipped/1008446160/3775545364\\3.dcm\n    rsna_clipped/1008446160/3775545364\\2.dcm\n    rsna_clipped/1008446160/3775545364\\1.dcm\nCluster 4:\n    rsna_clipped/1008446160/3775545364\\8.dcm\n    rsna_clipped/1008446160/3775545364\\7.dcm\n    rsna_clipped/1008446160/3775545364\\6.dcm\n    rsna_clipped/1008446160/3775545364\\5.dcm</em></p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F21070744%2F5cd4617727b06d4cf4c2a68d8dfcdfe3%2Fqq.png?generation=1723563844340495&amp;alt=media\" alt=\"\"></p>\n<p>support by upvoting -- I'm 16yrs I've tried😊 tnx</p>",
  "messages": [
    {
      "id": "2958025",
      "postDate": "08/13/2024 15:50:23",
      "content": "<p>`import os<br>\nimport numpy as np<br>\nimport pydicom<br>\nimport matplotlib.pyplot as plt<br>\nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection<br>\nfrom sklearn.cluster import KMeans</p>\n<h1>Function to load DICOM files and extract IOP and positions</h1>\n<p>def load_dicom_slices(directory):<br>\n    slices = []<br>\n    filepaths = []<br>\n    for filename in os.listdir(directory):<br>\n        if filename.endswith(\".dcm\"):<br>\n            filepath = os.path.join(directory, filename)<br>\n            ds = pydicom.dcmread(filepath)<br>\n            slices.append(ds)<br>\n            filepaths.append(filepath)<br>\n    return slices, filepaths</p>\n<p>def extract_iop_and_position(slices):<br>\n    iop_vectors = []<br>\n    positions = []<br>\n    for slice in slices:<br>\n        iop = np.array(slice.ImageOrientationPatient).reshape(2, 3)<br>\n        iop_normal = np.cross(iop[0], iop[1])  # Calculate normal vector<br>\n        position = np.array(slice.ImagePositionPatient)<br>\n        iop_vectors.append(iop_normal)<br>\n        positions.append(position)<br>\n    return np.array(iop_vectors), np.array(positions)</p>\n<p>def cluster_slices_by_iop(iop_vectors, n_clusters=5):<br>\n    kmeans = KMeans(n_clusters=n_clusters)<br>\n    labels = kmeans.fit_predict(iop_vectors)<br>\n    return labels</p>\n<p>def sort_slices_within_clusters(labels, positions, filepaths):<br>\n    sorted_slices = {}<br>\n    for cluster_label in np.unique(labels):<br>\n        cluster_indices = np.where(labels == cluster_label)[0]<br>\n        cluster_positions = positions[cluster_indices]<br>\n        # Sort based on the z-component of the position vector<br>\n        sorted_indices = np.argsort(cluster_positions[:, 2])<br>\n        sorted_slices[cluster_label] = [filepaths[idx] for idx in cluster_indices[sorted_indices]]<br>\n    return sorted_slices</p>\n<p>def print_cluster_file_paths(sorted_slices):<br>\n    for cluster_label, filepaths in sorted_slices.items():<br>\n        print(f\"Cluster {cluster_label}:\")<br>\n        for filepath in filepaths:<br>\n            print(f\"    {filepath}\")</p>\n<p>def plot_clusters(slices, labels, positions, sorted_slices):<br>\n    fig = plt.figure(figsize=(12, 6))</p>\n<pre><code>\nax1 = fig.add_subplot(121, =)\nax2 = fig.add_subplot(122, =)\n\n\ncolors = plt.cm.rainbow(np.linspace(0, 1, len(sorted_slices)))\n\n cluster_label, color  zip(sorted_slices.keys(), colors):\n     idx  range(len(sorted_slices[cluster_label])):\n        #  the DICOM slice  this index\n        filepath = sorted_slices[cluster_label][idx]\n        ds = pydicom.dcmread(filepath)\n\n        #  the 3 points that define the plane (corner points of the slice)\n        iop = np.array(ds.ImageOrientationPatient).reshape(2, 3)\n        ipp = np.array(ds.ImagePositionPatient)\n        row_dir = iop[0] * ds.Rows\n        col_dir = iop[1] * ds.Columns\n\n        p1 = ipp\n        p2 = ipp + row_dir\n        p3 = ipp + col_dir\n\n        # Plane defined by three points\n        vertices = [p1, p2, p2 + col_dir, p3]\n\n        # Create a new Poly3DCollection  each axis\n        plane1 = Poly3DCollection([vertices], =color, =0.3)\n        plane2 = Poly3DCollection([vertices], =color, =0.3)\n\n        ax1.add_collection3d(plane1)\n        ax2.add_collection3d(plane2)\n\n        # Plot the points\n        ax1.scatter(*p1, =)\n        ax2.scatter(*p1, =)\n\n\nax1.set_xlabel()\nax1.set_ylabel()\nax1.set_zlabel()\n\nax2.set_xlabel()\nax2.set_ylabel()\nax2.set_zlabel()\n\n\nax1.set_box_aspect([1, 1, 1])\nax2.set_box_aspect([1, 1, 1])\n\nplt.show()\n</code></pre>\n<h1>Main function to process the DICOM slices and visualize them</h1>\n<p>def process_and_plot_dicom_slices(directory, n_clusters=5):<br>\n    slices, filepaths = load_dicom_slices(directory)<br>\n    iop_vectors, positions = extract_iop_and_position(slices)<br>\n    labels = cluster_slices_by_iop(iop_vectors, n_clusters)<br>\n    sorted_slices = sort_slices_within_clusters(labels, positions, filepaths)<br>\n    print_cluster_file_paths(sorted_slices)  # Print file paths for each cluster<br>\n    plot_clusters(slices, labels, positions, sorted_slices)</p>\n<h1>Example usage</h1>\n<p>dicom_directory = \"rsna_clipped/1008446160/3775545364\"<br>\nprocess_and_plot_dicom_slices(dicom_directory, n_clusters=5)<br>\n`<br>\nThis code outputs the images grouped by their respective levels, organized into clusters. The rest of the process is straightforward.</p>\n<p><em>Cluster 0:\n    rsna_clipped/1008446160/3775545364\\13.dcm\n    rsna_clipped/1008446160/3775545364\\12.dcm\n    rsna_clipped/1008446160/3775545364\\11.dcm\n    rsna_clipped/1008446160/3775545364\\10.dcm\n    rsna_clipped/1008446160/3775545364\\9.dcm\nCluster 1:\n    rsna_clipped/1008446160/3775545364\\24.dcm\n    rsna_clipped/1008446160/3775545364\\23.dcm\n    rsna_clipped/1008446160/3775545364\\22.dcm\n    rsna_clipped/1008446160/3775545364\\21.dcm\n    rsna_clipped/1008446160/3775545364\\20.dcm\n    rsna_clipped/1008446160/3775545364\\19.dcm\nCluster 2:\n    rsna_clipped/1008446160/3775545364\\18.dcm\n    rsna_clipped/1008446160/3775545364\\17.dcm\n    rsna_clipped/1008446160/3775545364\\16.dcm\n    rsna_clipped/1008446160/3775545364\\15.dcm\n    rsna_clipped/1008446160/3775545364\\14.dcm\nCluster 3:\n    rsna_clipped/1008446160/3775545364\\4.dcm\n    rsna_clipped/1008446160/3775545364\\3.dcm\n    rsna_clipped/1008446160/3775545364\\2.dcm\n    rsna_clipped/1008446160/3775545364\\1.dcm\nCluster 4:\n    rsna_clipped/1008446160/3775545364\\8.dcm\n    rsna_clipped/1008446160/3775545364\\7.dcm\n    rsna_clipped/1008446160/3775545364\\6.dcm\n    rsna_clipped/1008446160/3775545364\\5.dcm</em></p>\n<p><img src=\"https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F21070744%2F5cd4617727b06d4cf4c2a68d8dfcdfe3%2Fqq.png?generation=1723563844340495&amp;alt=media\" alt=\"\"></p>\n<p>support by upvoting -- I'm 16yrs I've tried😊 tnx</p>",
      "rawMarkdown": "`import os\nimport numpy as np\nimport pydicom\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection\nfrom sklearn.cluster import KMeans\n\n# Function to load DICOM files and extract IOP and positions\ndef load_dicom_slices(directory):\n    slices = []\n    filepaths = []\n    for filename in os.listdir(directory):\n        if filename.endswith(\".dcm\"):\n            filepath = os.path.join(directory, filename)\n            ds = pydicom.dcmread(filepath)\n            slices.append(ds)\n            filepaths.append(filepath)\n    return slices, filepaths\n\ndef extract_iop_and_position(slices):\n    iop_vectors = []\n    positions = []\n    for slice in slices:\n        iop = np.array(slice.ImageOrientationPatient).reshape(2, 3)\n        iop_normal = np.cross(iop[0], iop[1])  # Calculate normal vector\n        position = np.array(slice.ImagePositionPatient)\n        iop_vectors.append(iop_normal)\n        positions.append(position)\n    return np.array(iop_vectors), np.array(positions)\n\ndef cluster_slices_by_iop(iop_vectors, n_clusters=5):\n    kmeans = KMeans(n_clusters=n_clusters)\n    labels = kmeans.fit_predict(iop_vectors)\n    return labels\n\ndef sort_slices_within_clusters(labels, positions, filepaths):\n    sorted_slices = {}\n    for cluster_label in np.unique(labels):\n        cluster_indices = np.where(labels == cluster_label)[0]\n        cluster_positions = positions[cluster_indices]\n        # Sort based on the z-component of the position vector\n        sorted_indices = np.argsort(cluster_positions[:, 2])\n        sorted_slices[cluster_label] = [filepaths[idx] for idx in cluster_indices[sorted_indices]]\n    return sorted_slices\n\ndef print_cluster_file_paths(sorted_slices):\n    for cluster_label, filepaths in sorted_slices.items():\n        print(f\"Cluster {cluster_label}:\")\n        for filepath in filepaths:\n            print(f\"    {filepath}\")\n\ndef plot_clusters(slices, labels, positions, sorted_slices):\n    fig = plt.figure(figsize=(12, 6))\n\n    # Create subplots for different views\n    ax1 = fig.add_subplot(121, projection='3d')\n    ax2 = fig.add_subplot(122, projection='3d')\n\n    # Define colors for clusters\n    colors = plt.cm.rainbow(np.linspace(0, 1, len(sorted_slices)))\n\n    for cluster_label, color in zip(sorted_slices.keys(), colors):\n        for idx in range(len(sorted_slices[cluster_label])):\n            # Get the DICOM slice for this index\n            filepath = sorted_slices[cluster_label][idx]\n            ds = pydicom.dcmread(filepath)\n\n            # Get the 3 points that define the plane (corner points of the slice)\n            iop = np.array(ds.ImageOrientationPatient).reshape(2, 3)\n            ipp = np.array(ds.ImagePositionPatient)\n            row_dir = iop[0] * ds.Rows\n            col_dir = iop[1] * ds.Columns\n\n            p1 = ipp\n            p2 = ipp + row_dir\n            p3 = ipp + col_dir\n\n            # Plane defined by three points\n            vertices = [p1, p2, p2 + col_dir, p3]\n\n            # Create a new Poly3DCollection for each axis\n            plane1 = Poly3DCollection([vertices], color=color, alpha=0.3)\n            plane2 = Poly3DCollection([vertices], color=color, alpha=0.3)\n\n            ax1.add_collection3d(plane1)\n            ax2.add_collection3d(plane2)\n\n            # Plot the points\n            ax1.scatter(*p1, color='k')\n            ax2.scatter(*p1, color='k')\n\n    # Set axis labels\n    ax1.set_xlabel('X')\n    ax1.set_ylabel('Y')\n    ax1.set_zlabel('Z')\n\n    ax2.set_xlabel('X')\n    ax2.set_ylabel('Y')\n    ax2.set_zlabel('Z')\n\n    # Set the aspect ratio of the plot to be equal\n    ax1.set_box_aspect([1, 1, 1])\n    ax2.set_box_aspect([1, 1, 1])\n\n    plt.show()\n\n# Main function to process the DICOM slices and visualize them\ndef process_and_plot_dicom_slices(directory, n_clusters=5):\n    slices, filepaths = load_dicom_slices(directory)\n    iop_vectors, positions = extract_iop_and_position(slices)\n    labels = cluster_slices_by_iop(iop_vectors, n_clusters)\n    sorted_slices = sort_slices_within_clusters(labels, positions, filepaths)\n    print_cluster_file_paths(sorted_slices)  # Print file paths for each cluster\n    plot_clusters(slices, labels, positions, sorted_slices)\n\n# Example usage\ndicom_directory = \"rsna_clipped/1008446160/3775545364\"\nprocess_and_plot_dicom_slices(dicom_directory, n_clusters=5)\n`\nThis code outputs the images grouped by their respective levels, organized into clusters. The rest of the process is straightforward.\n\n*Cluster 0:\n    rsna_clipped/1008446160/3775545364\\13.dcm\n    rsna_clipped/1008446160/3775545364\\12.dcm\n    rsna_clipped/1008446160/3775545364\\11.dcm\n    rsna_clipped/1008446160/3775545364\\10.dcm\n    rsna_clipped/1008446160/3775545364\\9.dcm\nCluster 1:\n    rsna_clipped/1008446160/3775545364\\24.dcm\n    rsna_clipped/1008446160/3775545364\\23.dcm\n    rsna_clipped/1008446160/3775545364\\22.dcm\n    rsna_clipped/1008446160/3775545364\\21.dcm\n    rsna_clipped/1008446160/3775545364\\20.dcm\n    rsna_clipped/1008446160/3775545364\\19.dcm\nCluster 2:\n    rsna_clipped/1008446160/3775545364\\18.dcm\n    rsna_clipped/1008446160/3775545364\\17.dcm\n    rsna_clipped/1008446160/3775545364\\16.dcm\n    rsna_clipped/1008446160/3775545364\\15.dcm\n    rsna_clipped/1008446160/3775545364\\14.dcm\nCluster 3:\n    rsna_clipped/1008446160/3775545364\\4.dcm\n    rsna_clipped/1008446160/3775545364\\3.dcm\n    rsna_clipped/1008446160/3775545364\\2.dcm\n    rsna_clipped/1008446160/3775545364\\1.dcm\nCluster 4:\n    rsna_clipped/1008446160/3775545364\\8.dcm\n    rsna_clipped/1008446160/3775545364\\7.dcm\n    rsna_clipped/1008446160/3775545364\\6.dcm\n    rsna_clipped/1008446160/3775545364\\5.dcm*\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F21070744%2F5cd4617727b06d4cf4c2a68d8dfcdfe3%2Fqq.png?generation=1723563844340495&alt=media)\n\nsupport by upvoting -- I'm 16yrs I've tried😊 tnx",
      "votes": null
    },
    {
      "id": "2974081",
      "postDate": "08/30/2024 09:18:58",
      "content": "<p>Hi,</p>\n<p>How did you handle study_ids with multiple axial folders ?</p>\n<p>Did you merge them or cluster them separately?</p>",
      "rawMarkdown": "Hi,\n\nHow did you handle study_ids with multiple axial folders ?\n\nDid you merge them or cluster them separately?",
      "votes": null
    }
  ],
  "comments": [
    {
      "id": 2974081,
      "author_name": "rohitchaudhari25",
      "author_url": "",
      "post_date": "08/30/2024 09:18:58",
      "content": "<p>Hi,</p>\n<p>How did you handle study_ids with multiple axial folders ?</p>\n<p>Did you merge them or cluster them separately?</p>",
      "votes": null,
      "replies": []
    }
  ],
  "raw_markdown_by_id": {
    "2958025": "`import os\nimport numpy as np\nimport pydicom\nimport matplotlib.pyplot as plt\nfrom mpl_toolkits.mplot3d.art3d import Poly3DCollection\nfrom sklearn.cluster import KMeans\n\n# Function to load DICOM files and extract IOP and positions\ndef load_dicom_slices(directory):\n    slices = []\n    filepaths = []\n    for filename in os.listdir(directory):\n        if filename.endswith(\".dcm\"):\n            filepath = os.path.join(directory, filename)\n            ds = pydicom.dcmread(filepath)\n            slices.append(ds)\n            filepaths.append(filepath)\n    return slices, filepaths\n\ndef extract_iop_and_position(slices):\n    iop_vectors = []\n    positions = []\n    for slice in slices:\n        iop = np.array(slice.ImageOrientationPatient).reshape(2, 3)\n        iop_normal = np.cross(iop[0], iop[1])  # Calculate normal vector\n        position = np.array(slice.ImagePositionPatient)\n        iop_vectors.append(iop_normal)\n        positions.append(position)\n    return np.array(iop_vectors), np.array(positions)\n\ndef cluster_slices_by_iop(iop_vectors, n_clusters=5):\n    kmeans = KMeans(n_clusters=n_clusters)\n    labels = kmeans.fit_predict(iop_vectors)\n    return labels\n\ndef sort_slices_within_clusters(labels, positions, filepaths):\n    sorted_slices = {}\n    for cluster_label in np.unique(labels):\n        cluster_indices = np.where(labels == cluster_label)[0]\n        cluster_positions = positions[cluster_indices]\n        # Sort based on the z-component of the position vector\n        sorted_indices = np.argsort(cluster_positions[:, 2])\n        sorted_slices[cluster_label] = [filepaths[idx] for idx in cluster_indices[sorted_indices]]\n    return sorted_slices\n\ndef print_cluster_file_paths(sorted_slices):\n    for cluster_label, filepaths in sorted_slices.items():\n        print(f\"Cluster {cluster_label}:\")\n        for filepath in filepaths:\n            print(f\"    {filepath}\")\n\ndef plot_clusters(slices, labels, positions, sorted_slices):\n    fig = plt.figure(figsize=(12, 6))\n\n    # Create subplots for different views\n    ax1 = fig.add_subplot(121, projection='3d')\n    ax2 = fig.add_subplot(122, projection='3d')\n\n    # Define colors for clusters\n    colors = plt.cm.rainbow(np.linspace(0, 1, len(sorted_slices)))\n\n    for cluster_label, color in zip(sorted_slices.keys(), colors):\n        for idx in range(len(sorted_slices[cluster_label])):\n            # Get the DICOM slice for this index\n            filepath = sorted_slices[cluster_label][idx]\n            ds = pydicom.dcmread(filepath)\n\n            # Get the 3 points that define the plane (corner points of the slice)\n            iop = np.array(ds.ImageOrientationPatient).reshape(2, 3)\n            ipp = np.array(ds.ImagePositionPatient)\n            row_dir = iop[0] * ds.Rows\n            col_dir = iop[1] * ds.Columns\n\n            p1 = ipp\n            p2 = ipp + row_dir\n            p3 = ipp + col_dir\n\n            # Plane defined by three points\n            vertices = [p1, p2, p2 + col_dir, p3]\n\n            # Create a new Poly3DCollection for each axis\n            plane1 = Poly3DCollection([vertices], color=color, alpha=0.3)\n            plane2 = Poly3DCollection([vertices], color=color, alpha=0.3)\n\n            ax1.add_collection3d(plane1)\n            ax2.add_collection3d(plane2)\n\n            # Plot the points\n            ax1.scatter(*p1, color='k')\n            ax2.scatter(*p1, color='k')\n\n    # Set axis labels\n    ax1.set_xlabel('X')\n    ax1.set_ylabel('Y')\n    ax1.set_zlabel('Z')\n\n    ax2.set_xlabel('X')\n    ax2.set_ylabel('Y')\n    ax2.set_zlabel('Z')\n\n    # Set the aspect ratio of the plot to be equal\n    ax1.set_box_aspect([1, 1, 1])\n    ax2.set_box_aspect([1, 1, 1])\n\n    plt.show()\n\n# Main function to process the DICOM slices and visualize them\ndef process_and_plot_dicom_slices(directory, n_clusters=5):\n    slices, filepaths = load_dicom_slices(directory)\n    iop_vectors, positions = extract_iop_and_position(slices)\n    labels = cluster_slices_by_iop(iop_vectors, n_clusters)\n    sorted_slices = sort_slices_within_clusters(labels, positions, filepaths)\n    print_cluster_file_paths(sorted_slices)  # Print file paths for each cluster\n    plot_clusters(slices, labels, positions, sorted_slices)\n\n# Example usage\ndicom_directory = \"rsna_clipped/1008446160/3775545364\"\nprocess_and_plot_dicom_slices(dicom_directory, n_clusters=5)\n`\nThis code outputs the images grouped by their respective levels, organized into clusters. The rest of the process is straightforward.\n\n*Cluster 0:\n    rsna_clipped/1008446160/3775545364\\13.dcm\n    rsna_clipped/1008446160/3775545364\\12.dcm\n    rsna_clipped/1008446160/3775545364\\11.dcm\n    rsna_clipped/1008446160/3775545364\\10.dcm\n    rsna_clipped/1008446160/3775545364\\9.dcm\nCluster 1:\n    rsna_clipped/1008446160/3775545364\\24.dcm\n    rsna_clipped/1008446160/3775545364\\23.dcm\n    rsna_clipped/1008446160/3775545364\\22.dcm\n    rsna_clipped/1008446160/3775545364\\21.dcm\n    rsna_clipped/1008446160/3775545364\\20.dcm\n    rsna_clipped/1008446160/3775545364\\19.dcm\nCluster 2:\n    rsna_clipped/1008446160/3775545364\\18.dcm\n    rsna_clipped/1008446160/3775545364\\17.dcm\n    rsna_clipped/1008446160/3775545364\\16.dcm\n    rsna_clipped/1008446160/3775545364\\15.dcm\n    rsna_clipped/1008446160/3775545364\\14.dcm\nCluster 3:\n    rsna_clipped/1008446160/3775545364\\4.dcm\n    rsna_clipped/1008446160/3775545364\\3.dcm\n    rsna_clipped/1008446160/3775545364\\2.dcm\n    rsna_clipped/1008446160/3775545364\\1.dcm\nCluster 4:\n    rsna_clipped/1008446160/3775545364\\8.dcm\n    rsna_clipped/1008446160/3775545364\\7.dcm\n    rsna_clipped/1008446160/3775545364\\6.dcm\n    rsna_clipped/1008446160/3775545364\\5.dcm*\n\n![](https://www.googleapis.com/download/storage/v1/b/kaggle-forum-message-attachments/o/inbox%2F21070744%2F5cd4617727b06d4cf4c2a68d8dfcdfe3%2Fqq.png?generation=1723563844340495&alt=media)\n\nsupport by upvoting -- I'm 16yrs I've tried😊 tnx",
    "2974081": "Hi,\n\nHow did you handle study_ids with multiple axial folders ?\n\nDid you merge them or cluster them separately?"
  },
  "source": "meta"
}