paint-brush
Können Sie medizinische Daten (MR, CT, Röntgen) in Python öffnen und Tumore mit KI finden?! Vielleichtvon@thebojda
3,808 Lesungen
3,808 Lesungen

Können Sie medizinische Daten (MR, CT, Röntgen) in Python öffnen und Tumore mit KI finden?! Vielleicht

von Laszlo Fazekas8m2024/04/23
Read on Terminal Reader

Zu lang; Lesen

Wenn ein Programmierer von der Verarbeitung medizinischer Daten hört, könnte er denken, dass es sich um etwas Ernstes handelt, etwas, mit dem nur Universitäten und Forschungsinstitute umgehen können (das dachte ich zumindest). Wie Sie sehen, sprechen wir von einfachen Graustufenbildern, die sehr einfach zu verarbeiten sind und sich ideal für Dinge wie die Verarbeitung neuronaler Netze eignen.
featured image - Können Sie medizinische Daten (MR, CT, Röntgen) in Python öffnen und Tumore mit KI finden?! Vielleicht
Laszlo Fazekas HackerNoon profile picture
0-item


Vor ein paar Tagen wurde ich einer Magnetresonanztomographie unterzogen. Ich wurde in eine große Röhre geschoben und 15 Minuten lang brummte, surrte und klickte die Maschine um mich herum. Am Ende der Untersuchung erhielt ich eine CD mit den Daten. Was macht ein guter Entwickler in einer solchen Situation? Natürlich beginnt er, sobald er nach Hause kommt, die Daten zu untersuchen und darüber nachzudenken, wie er sie mit Python extrahieren könnte.


Die CD enthielt eine Reihe von DLLs, eine EXE und einige zusätzliche Dateien für einen Windows-Viewer, die unter Linux offensichtlich nutzlos sind. Der Knackpunkt befand sich in einem Ordner namens DICOM. Er enthielt eine Reihe von Dateien ohne Erweiterung in acht Ordnern. ChatGPT half mir herauszufinden, dass DICOM ein Standardformat ist, das normalerweise zum Speichern von MRT-, CT- und Röntgenbildern verwendet wird. Im Wesentlichen ist es ein einfaches Verpackungsformat, das Graustufenbilder und einige Metadaten enthält.


Mit dem folgenden Code können Sie die Dateien einfach im PNG-Format exportieren:


 import os import pydicom from PIL import Image import sys def save_image(pixel_array, output_path): if pixel_array.dtype != 'uint8': pixel_array = ((pixel_array - pixel_array.min()) / (pixel_array.max() - pixel_array.min()) * 255).astype('uint8') img = Image.fromarray(pixel_array) img.save(output_path) print(f"Saved image to {output_path}") def process_dicom_directory(dicomdir_path, save_directory): if not os.path.exists(save_directory): os.makedirs(save_directory) dicomdir = pydicom.dcmread(dicomdir_path) for patient_record in dicomdir.patient_records: if 'PatientName' in patient_record: print(f"Patient: {patient_record.PatientName}") for study_record in patient_record.children: if 'StudyDate' in study_record: print(f"Study: {study_record.StudyDate}") for series_record in study_record.children: for image_record in series_record.children: if 'ReferencedFileID' in image_record: file_id = list(map(str, image_record.ReferencedFileID)) file_id_path = os.path.join(*file_id) print(f"Image: {file_id_path}") image_path = os.path.join(os.path.dirname(dicomdir_path), file_id_path) modified_filename = '_'.join(file_id) + '.png' image_save_path = os.path.join(save_directory, modified_filename) try: img_data = pydicom.dcmread(image_path) print("DICOM image loaded successfully.") save_image(img_data.pixel_array, image_save_path) except FileNotFoundError as e: print(f"Failed to read DICOM file at {image_path}: {e}") except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": if len(sys.argv) < 3: print("Usage: python dicomsave.py <path_to_DICOMDIR> <path_to_save_images>") sys.exit(1) dicomdir_path = sys.argv[1] save_directory = sys.argv[2] process_dicom_directory(dicomdir_path, save_directory)


Der Code erwartet zwei Parameter. Der erste ist der Pfad zur DICOMDIR-Datei und der zweite ist ein Verzeichnis, in dem die Bilder im PNG-Format gespeichert werden.


Zum Lesen der DICOM-Dateien verwenden wir die Pydicom- Bibliothek. Die Struktur wird mit der Funktion pydicom.dcmread geladen, aus der Metadaten (wie der Name des Patienten) und Studien mit den Bildern extrahiert werden können. Die Bilddaten können auch mit dcmread gelesen werden. Die Rohdaten sind über das Pixelarray- Feld zugänglich, das die Funktion save_image in PNG konvertiert. Es ist nicht allzu kompliziert.


Das Ergebnis sind einige quadratische (normalerweise 512 x 512) Graustufenbilder, die später problemlos verwendet werden können.


Warum hielt ich es für wichtig, diese Kurzgeschichte über mein Abenteuer mit dem DICOM-Format zu schreiben? Wenn ein Programmierer von der Verarbeitung medizinischer Daten hört, könnte er denken, dass es sich um etwas Ernstes handelt, etwas, mit dem nur Universitäten und Forschungsinstitute umgehen können (zumindest dachte ich das). Wie Sie sehen, sprechen wir von einfachen Graustufenbildern, die sehr einfach zu verarbeiten sind und sich ideal für Dinge wie die Verarbeitung neuronaler Netze eignen.


Bedenken Sie die Möglichkeiten, die sich dadurch eröffnen. Für etwas wie einen einfachen Tumordetektor benötigen Sie lediglich ein relativ einfaches Faltungsnetzwerk und eine ausreichende Anzahl von Beispielen. In Wirklichkeit unterscheidet sich die Aufgabe nicht wesentlich von der Erkennung von Hunden oder Katzen in Bildern.


Um zu verdeutlichen, wie wahr das ist, möchte ich ein Beispiel geben. Nach einer kurzen Suche auf Kaggle fand ich ein Notizbuch , in dem Hirntumore anhand von MRT-Daten (Graustufenbilder) klassifiziert werden. Der Datensatz kategorisiert die Bilder in vier Gruppen: drei Arten von Hirntumoren und eine vierte Kategorie mit Bildern gesunder Gehirne. Die Architektur des Netzwerks ist wie folgt:


 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv2d (Conv2D) │ (None, 164, 164, 64) │ 1,664 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 54, 54, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_1 (Conv2D) │ (None, 50, 50, 64) │ 102,464 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_1 (MaxPooling2D) │ (None, 16, 16, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_2 (Conv2D) │ (None, 13, 13, 128) │ 131,200 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_2 (MaxPooling2D) │ (None, 6, 6, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_3 (Conv2D) │ (None, 3, 3, 128) │ 262,272 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_3 (MaxPooling2D) │ (None, 1, 1, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten (Flatten) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 512) │ 66,048 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 4) │ 2,052 │ └─────────────────────────────────┴────────────────────────┴───────────────┘


Wie Sie sehen, bestehen die ersten Schichten aus einem Convolution- und Max-Pooling-Sandwich, das Tumormuster extrahiert, gefolgt von zwei dichten Schichten, die die Klassifizierung durchführen. Dies ist genau dieselbe Architektur, die im CNN-Beispielcode von TensorFlow verwendet wird, der den CIFAR-10-Datensatz verwendet. Ich erinnere mich gut daran, da es eines der ersten neuronalen Netzwerke war, mit denen ich in Berührung gekommen bin. Der CIFAR-10- Datensatz enthält 60.000 Bilder, die in zehn Klassen kategorisiert sind, darunter zwei Klassen für Hunde und Katzen, wie ich bereits erwähnt habe. Die Architektur des Netzwerks sieht folgendermaßen aus:


 Model: “sequential” _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 30, 30, 32) 896 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 15, 15, 32) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 13, 13, 64) 18496 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 6, 6, 64) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 4, 4, 64) 36928 _________________________________________________________________ flatten (Flatten) (None, 1024) 0 _________________________________________________________________ dense (Dense) (None, 64) 65600 _________________________________________________________________ dense_1 (Dense) (None, 10) 650 ================================================================= Total params: 122,570 Trainable params: 122,570 Non-trainable params: 0 _________________________________________________________________


Es ist klar, dass wir es mit derselben Architektur zu tun haben, nur mit leicht unterschiedlichen Parametern. Das Erkennen von Hirntumoren in MRT-Bildern ist also tatsächlich nicht viel schwieriger als das Identifizieren von Katzen oder Hunden auf Bildern. Darüber hinaus ist das erwähnte Kaggle-Notebook in der Lage, Tumore mit einer Effektivität von 99 % zu klassifizieren!


Ich möchte lediglich darauf hinweisen, wie einfach es in bestimmten Fällen sein kann, medizinische Daten zu extrahieren und zu verarbeiten und dass scheinbar komplexe Probleme, wie etwa die Erkennung von Gehirntumoren, oft recht effektiv mit einfachen, herkömmlichen Lösungen angegangen werden können.


Daher möchte ich jeden ermutigen, medizinische Daten nicht zu scheuen. Wie Sie sehen, handelt es sich um relativ einfache Formate und mit relativ einfachen, etablierten Technologien (Faltungsnetze, Vision Transformers usw.) kann hier eine erhebliche Wirkung erzielt werden. Wenn Sie in Ihrer Freizeit nur als Hobby an einem Open-Source-Gesundheitsprojekt teilnehmen und das verwendete neuronale Netzwerk auch nur geringfügig verbessern können, können Sie möglicherweise Leben retten!