paint-brush
의료 데이터(MR, CT, X-Ray)를 Python으로 열고 AI로 종양을 찾을 수 있습니까?! 아마도~에 의해@thebojda
3,548 판독값
3,548 판독값

의료 데이터(MR, CT, X-Ray)를 Python으로 열고 AI로 종양을 찾을 수 있습니까?! 아마도

~에 의해 Laszlo Fazekas8m2024/04/23
Read on Terminal Reader

너무 오래; 읽다

프로그래머가 의료 데이터 처리에 대해 들으면 그것이 대학이나 연구 기관만이 처리할 수 있는 심각한 일이라고 생각할 수도 있습니다(적어도 저는 그렇게 생각했습니다). 보시다시피, 우리는 처리하기가 매우 쉽고 신경망 처리와 같은 작업에 이상적인 간단한 회색조 이미지에 대해 이야기하고 있습니다.
featured image - 의료 데이터(MR, CT, X-Ray)를 Python으로 열고 AI로 종양을 찾을 수 있습니까?! 아마도
Laszlo Fazekas HackerNoon profile picture
0-item


며칠 전 MRI 검사를 받았습니다. 그들은 나를 큰 튜브에 밀어넣었고, 15분 동안 내 주변의 기계가 윙윙거리고 윙윙거리며 딸깍하는 소리를 냈습니다. 시험이 끝나고 데이터가 담긴 CD를 받았습니다. 좋은 개발자는 이런 상황에서 무엇을 합니까? 물론 집에 도착하자마자 데이터를 조사하고 Python 을 사용하여 데이터를 추출하는 방법에 대해 생각하기 시작합니다.


CD에는 여러 개의 DLL, EXE 및 Windows 뷰어용 추가 파일이 포함되어 있었는데, 이는 분명히 Linux에서는 쓸모가 없습니다. 핵심은 DICOM이라는 폴더에 있었습니다. 8개의 폴더에 걸쳐 확장자가 없는 일련의 파일을 보관했습니다. ChatGPT는 DICOM이 MRI, CT 및 X-ray 이미지를 저장하는 데 일반적으로 사용되는 표준 형식이라는 것을 파악하는 데 도움이 되었습니다. 기본적으로 이는 일부 메타데이터와 함께 회색조 이미지를 포함하는 간단한 패키징 형식입니다.


다음 코드를 사용하면 파일을 PNG 형식으로 쉽게 내보낼 수 있습니다.


 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)


코드에는 두 개의 매개변수가 필요합니다. 첫 번째는 DICOMDIR 파일의 경로이고 두 번째는 이미지가 PNG 형식으로 저장될 디렉터리입니다.


DICOM 파일을 읽으려면 Pydicom 라이브러리를 사용합니다. 구조는 pydicom.dcmread 함수를 사용하여 로드되며, 여기에서 메타데이터(예: 환자 이름)와 이미지가 포함된 연구를 추출할 수 있습니다. 이미지 데이터는 dcmread 를 사용하여 읽을 수도 있습니다. 원시 데이터는 save_image 함수가 PNG로 변환하는 pixelarray 필드를 통해 액세스할 수 있습니다. 너무 복잡하지 않습니다.


결과는 나중에 쉽게 활용할 수 있는 몇 개의 정사각형(일반적으로 512x512) 회색조 이미지입니다.


DICOM 형식을 사용하여 나의 모험에 대한 이 짧은 이야기를 쓰는 것이 왜 중요하다고 생각했습니까? 프로그래머가 의료 데이터 처리에 대해 들으면 그것이 대학이나 연구 기관만이 처리할 수 있는 심각한 일이라고 생각할 수도 있습니다(적어도 저는 그렇게 생각했습니다). 보시다시피, 우리는 처리하기가 매우 쉽고 신경망 처리와 같은 작업에 이상적인 간단한 회색조 이미지에 대해 이야기하고 있습니다.


이것이 열리는 가능성을 고려하십시오. 간단한 종양 탐지기와 같은 경우 필요한 것은 상대적으로 간단한 컨벌루션 네트워크와 충분한 수의 샘플뿐입니다. 실제로 이 작업은 이미지 속 개나 고양이를 인식하는 것과 크게 다르지 않습니다.


이것이 얼마나 사실인지 설명하기 위해 예를 들어 보겠습니다. Kaggle에서 잠깐 검색한 결과 MRI 데이터(회색조 이미지)를 기반으로 뇌종양을 분류한 노트북을 발견했습니다 . 데이터 세트는 이미지를 4가지 그룹, 즉 세 가지 유형의 뇌종양과 건강한 뇌 이미지가 포함된 네 번째 카테고리로 분류합니다. 네트워크의 아키텍처는 다음과 같습니다.


 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ 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 │ └─────────────────────────────────┴────────────────────────┴───────────────┘


보시다시피, 처음 몇 개의 레이어는 종양 패턴을 추출하는 컨볼루션 및 최대 풀링 샌드위치로 구성되며, 그 다음에는 분류를 수행하는 두 개의 밀집 레이어가 있습니다. 이는 CIFAR-10 데이터세트를 사용하는 TensorFlow의 CNN 샘플 코드 에 사용된 아키텍처와 정확히 동일합니다. 제가 처음 접한 신경망 중 하나였기 때문에 잘 기억합니다. CIFAR-10 데이터 세트에는 앞서 언급한 대로 개와 고양이에 대한 두 가지 클래스를 포함하여 10가지 클래스로 분류된 60,000개의 이미지가 포함되어 있습니다. 네트워크 아키텍처는 다음과 같습니다.


 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 _________________________________________________________________


매개변수가 약간 다를 뿐 동일한 아키텍처를 다루고 있다는 것이 분명하므로 MRI 이미지에서 뇌종양을 인식하는 것은 실제로 사진에서 고양이나 개를 식별하는 것보다 훨씬 어렵지 않습니다. 게다가 언급된 Kaggle 노트북은 99%의 효율성으로 종양을 분류할 수 있습니다!


저는 특정 경우에 의료 데이터를 추출하고 처리하는 것이 얼마나 간단할 수 있는지, 그리고 뇌종양 감지와 같이 복잡해 보이는 문제가 간단하고 전통적인 솔루션을 통해 어떻게 매우 효과적으로 해결될 수 있는지 지적하고 싶습니다.


그러므로 나는 모든 사람이 의료 데이터를 부끄러워하지 않도록 격려하고 싶습니다. 보시다시피, 우리는 상대적으로 단순한 형식을 다루고 있으며 상대적으로 간단하고 잘 확립된 기술(컨벌루션 네트워크, 비전 변환기 등)을 사용하여 여기서 상당한 영향을 미칠 수 있습니다. 여가 시간에 취미로 오픈 소스 의료 프로젝트에 참여하고 사용되는 신경망을 약간만 개선할 수 있다면 잠재적으로 생명을 구할 수 있습니다!