Python Code

DICOM 파일 전처리

Kimhj 2024. 1. 19. 13:25
  • dicom meta 데이터를 활용한 이미지 전처리
- 실제 dicom 이미지에 저장된 값을 image값으로 변환하기
- dicom 내의 x좌표, y좌표 -> pixel_array[y좌표][x좌표]로 불러오기
- RescaleSlope,RescaleIntercept 는 디스크에 저장된 픽셀에서 메모리 표현으로의 선형 변환을 지정하는 태그
- CT 이미지는 일반적으로 부호없는 변수로 저장되기에 음수로도 저장되는 Houndsfield 단위에 대한 변환을 위해 후처리가 필요
1. Low-level 수준에서의 dicom 이미지 전처리
    - RescaleSlope, RescaleIntercept를 활용하여 Dicnom 저장된 이미지 값으로 변환
    - Dicom header의 Bits_Stored를 활용하여 normalizaion
    - WindowWidth(너비), WindowCenter(중앙값)를 활용하여 조직에 맞게 강조되도록 이미지 수정
    - Normalization

2. pydicom을 활용 dicom 이미지 전처리
	- apply_modality_lut
      - Modality_lut 모달리티에 대한 LUT(Look Up Table)을 활용해 변환(RescaleSlope, RescaleIntercept)
  - apply_voi_lut
      - LUT에 정의된 보고자 하는 조직에 맞게 강조(WindowWidth, WindowCenter)
      
      
      # 1. Row-Level 수준에서의 이미지 전처리
ds = pydicom.read_file(Dicom path)

# apply_modality_lut와 동일
if(('RescaleSlope' in ds) and ('RescaleIntercept' in ds)):
    pixel_array = (ds.RescaleSlope * ds.pixel_array) + ds.RescaleIntercept

# apply_voi_lut
y_min = 0
y_max = 2**ds.BitsStored - 1

pixel_array = pixel_array.astype("float64")

slope = ds.get("RescaleSlope", None)
intercept = ds.get("RescaleIntercept", None)
if slope is not None and intercept is not None:
    ds.RescaleSlope = cast(float, ds.RescaleSlope)
    ds.RescaleIntercept = cast(float, ds.RescaleIntercept)
    y_min = y_min * ds.RescaleSlope + ds.RescaleIntercept
    y_max = y_max * ds.RescaleSlope + ds.RescaleIntercept

y_range = y_max - y_min

elem = ds["WindowCenter"]
center = float(elem.value[0]) if elem.VM > 1 else elem.value
center = cast(float, center)
elem = ds["WindowWidth"]
width = float(elem.value[0]) if elem.VM > 1 else elem.value
width = cast(float, width)

center -= 0.5
width -= 1

below = pixel_array <= (center - width / 2)
above = pixel_array > (center + width / 2)
between = np.logical_and(~below, ~above)        # AND 연산

pixel_array[below] = y_min
pixel_array[above] = y_max
if between.any():
    pixel_array[between] = ((pixel_array[between] - center) / width + 0.5) * y_range + y_min
    
# 2. pydicom을 활용한 이미지 전처리
ds = pydicom.read_file(Dicom path)
img = ds.pixel_array
img = apply_modality_lut(img, ds)  # RescaleSlope, RescaleIntercept
img = apply_voi_lut(img, ds)       # bits_stored 및 WindowSlope, WindowWidth 영상 강조하기
!pip install dicom2nifti
import dicom2nifti

dicom_directory = 'path'
output_directory = 'path'

dicom2nifti.convert_directory(dicom_directory, output_directory)

 

!pip install dicom2nifti
import dicom2nifti

dicom_directory = 'path'
output_directory = 'path'

dicom2nifti.convert_directory(dicom_directory, output_directory)

 

 

 

pip install pydicom
import pydicom

# Data Read (key-value 쌍을 가지는 dict 형태로 출력)
dcm_data=pydicom.dcmread('path')
dcm_data

 

 

 

# 키워드를 통해 표준 요소에 액세스할 수 있음 

dcm_data['SOPInstanceUID']
dcm_data.SOPInstanceUID

# 요소는 multi-valued일 수 있음(VM > 1)
dcm_data.ImageType

dcm_data.file_meta

 

 

  • Load 옵션
    • Img array가 무거우므로 로드 시 out of memory 발생할 수 있음 → header만 불러와 탐색하기
# option 
stop_before_pixels=True
specific_tags=['header1', 'header2', ...]

 

  • Image Load
def display_dicom_images(dcm_folder):
    # 리스트에 dcm 파일들을 저장
    dcm_files = [f for f in os.listdir(dcm_folder) if f.endswith(".dcm")]

    # 모든 DICOM 파일에 대해 루프
    for dcm_file in dcm_files:
        # DICOM 파일 경로 생성
        dcm_path = os.path.join(dcm_folder, dcm_file)

        # Pydicom을 사용하여 DICOM 파일 읽기
        dicom = pydicom.dcmread(dcm_path)

        # DICOM 이미지 추출
        image_array = dicom.pixel_array

        # 이미지 출력
        plt.imshow(image_array, cmap='gray')
        plt.title(f"DICOM Image: {dcm_file}")
        plt.show()

folder_path = 'path'
display_dicom_images(folder_path)