Cara membaca banyak gambar dicom dengan python

Pilih situs web untuk mendapatkan konten terjemahan jika tersedia dan lihat acara dan penawaran lokal. Berdasarkan lokasi Anda, sebaiknya pilih.

Anda juga dapat memilih situs web dari daftar berikut

Cara Mendapatkan Performa Situs Terbaik

Pilih situs China (dalam bahasa China atau Inggris) untuk kinerja situs terbaik. Situs negara MathWorks lainnya tidak dioptimalkan untuk kunjungan dari lokasi Anda

Dalam tutorial ini, saya akan melalui panduan langkah demi langkah tentang cara menerapkan metode pengelompokan statistik, algoritme grafik komputer, dan teknik pemrosesan gambar ke gambar medis untuk membantu memahami dan memvisualisasikan data dalam 2D ​​dan 3D (semua kode . )

Langkah 1. Instal Paket yang Diperlukan

Dua cara umum untuk menginstal paket menggunakan conda atau pip. Secara pribadi, saya pikir. mengapa tidak keduanya?

  • Piton 3. 6 (Saya menemukan versi lebih besar dari 3. 6 untuk memiliki masalah kompatibilitas dengan pydicom)
  • pydicom > untuk membaca file DICOM
  • numpy > untuk aplikasi komputasi
  • scipy > juga untuk aplikasi komputasi
  • skimage > untuk fungsi pemrosesan gambar
  • matplotlib -> untuk visualisasi
  • plotly > untuk visualisasi interaktif (lihat catatan di bawah sebelum menginstal)
  • ipywidget > untuk plot interaktif

*CATATAN. Untuk menggunakan plotly, Anda harus melakukannya. (1. ) Instal semua paket/ekstensi yang diperlukan dengan mengikuti petunjuk ini. (2. ) daftar untuk mendapatkan akun gratis dan aktifkan kunci Anda dengan mengikuti petunjuk ini (hanya baca bagian 'Inisialisasi untuk Pemetaan Online')

Langkah 2. Memuat Data DICOM

Selamat. Anda melewati bagian terburuk… menginstal paket. Untuk tutorial selanjutnya, saya akan menggunakan CT scan dada dan akan menjalankan skrip saya di notebook jupyter

Pertama mari impor paket yang diperlukan

# common packages 
import numpy as np
import os
import copy
from math import *
import matplotlib.pyplot as plt
from functools import reduce
# reading in dicom files
import pydicom
# skimage image processing packages
from skimage import measure, morphology
from skimage.morphology import ball, binary_closing
from skimage.measure import label, regionprops
# scipy linear algebra functions
from scipy.linalg import norm
import scipy.ndimage
# ipywidgets for some interactive plots
from ipywidgets.widgets import *
import ipywidgets as widgets
# plotly 3D interactive graphs
import plotly
from plotly.graph_objs import *
import chart_studio.plotly as py
# set plotly credentials here
# this allows you to send results to your account plotly.tools.set_credentials_file(username=your_username, api_key=your_key)

Selanjutnya, mari muat gambar DICOM Anda

def load_scan(path):
slices = [pydicom.dcmread(path + ‘/’ + s) for s in
os.listdir(path)]
slices = [s for s in slices if ‘SliceLocation’ in s]
slices.sort(key = lambda x: int(x.InstanceNumber))
try:
slice_thickness = np.abs(slices[0].ImagePositionPatient[2] —
slices[1].ImagePositionPatient[2])
except:
slice_thickness = np.abs(slices[0].SliceLocation —
slices[1].SliceLocation)
for s in slices:
s.SliceThickness = slice_thickness
return slices
def get_pixels_hu(scans):
image = np.stack([s.pixel_array for s in scans])
image = image.astype(np.int16)
# Set outside-of-scan pixels to 0
# The intercept is usually -1024, so air is approximately 0
image[image == -2000] = 0

# Convert to Hounsfield units (HU)
intercept = scans[0].RescaleIntercept
slope = scans[0].RescaleSlope

if slope != 1:
image = slope * image.astype(np.float64)
image = image.astype(np.int16)

image += np.int16(intercept)

return np.array(image, dtype=np.int16)
_

Jalankan kode berikut untuk mengekstrak piksel DICOM untuk setiap lokasi irisan dan tampilkan satu irisan

# set path and load files 
path = ‘path/to/your/dicom/directory/’
patient_dicom = load_scan(path)
patient_pixels = get_pixels_hu(patient_dicom)
#sanity check
plt.imshow(patient_pixels[326], cmap=plt.cm.bone)

Contoh irisan CT scan DadaLangkah 3. Pengolahan citra

Mari gunakan beberapa operasi thresholding dan morfologis untuk mensegmentasi paru-paru saja dari dada

def largest_label_volume(im, bg=-1):
vals, counts = np.unique(im, return_counts=True)
counts = counts[vals != bg]
vals = vals[vals != bg]
if len(counts) > 0:
return vals[np.argmax(counts)]
else:
return None
def segment_lung_mask(image, fill_lung_structures=True):
# not actually binary, but 1 and 2.
# 0 is treated as background, which we do not want
binary_image = np.array(image >= -700, dtype=np.int8)+1
labels = measure.label(binary_image)

# Pick the pixel in the very corner to determine which label is
air.
# Improvement: Pick multiple background labels from around the
patient
# More resistant to “trays” on which the patient lays cutting
the air around the person in half
background_label = labels[0,0,0]

# Fill the air around the person
binary_image[background_label == labels] = 2

# Method of filling the lung structures (that is superior to
# something like morphological closing)
if fill_lung_structures:
# For every slice we determine the largest solid structure
for i, axial_slice in enumerate(binary_image):
axial_slice = axial_slice — 1
labeling = measure.label(axial_slice)
l_max = largest_label_volume(labeling, bg=0)

if l_max is not None: #This slice contains some lung
binary_image[i][labeling != l_max] = 1
binary_image -= 1 #Make the image actual binary
binary_image = 1-binary_image # Invert it, lungs are now 1

# Remove other air pockets inside body
labels = measure.label(binary_image, background=0)
l_max = largest_label_volume(labels, bg=0)
if l_max is not None: # There are air pockets
binary_image[labels != l_max] = 0

return binary_image

Dengan menjalankan kode di bawah ini, Anda menggunakan fungsi skimage dari atas untuk membuat topeng yang menutupi paru-paru. Kami akan menggunakan keduanya fill_lung_structures=True dan fill_lung_structures=False, untuk mengisolasi paru-paru dan struktur internal. Mari jalankan kode di bawah ini, dan tampilkan contoh mengisolasi paru-paru dari dada

# get masks 
segmented_lungs = segment_lung_mask(patient_pixels,
fill_lung_structures=False)
segmented_lungs_fill = segment_lung_mask(patient_pixels,
fill_lung_structures=True)
internal_structures = segmented_lungs_fill - segmented_lungs
# isolate lung from chest
copied_pixels = copy.deepcopy(patient_pixels)
for i, mask in enumerate(segmented_lungs_fill):
get_high_vals = mask == 0
copied_pixels[i][get_high_vals] = 0
seg_lung_pixels = copied_pixels
# sanity check
plt.imshow(seg_lung_pixels[326], cmap=plt.cm.bone)
_

Paru Tersegmentasi (masih mempertahankan nilai piksel HU asli)

Jika terlihat seperti ini, maka sempurna. Anda baru saja mengisolasi paru-paru dari sisa pemindaian. Jangan khawatir tentang topengnya, saya akan menunjukkan beberapa visualisasi nanti

Metode ekstraksi fitur yang kuat menggunakan GK Clustering

Mengapa berhenti di paru-paru saja? . Tergantung pada tugas yang Anda berikan, Anda mungkin ingin menganalisis wilayah pemindaian yang lebih spesifik. Salah satu cara yang mungkin untuk melakukannya adalah menggunakan GK Clustering

class GK:
def __init__(self, n_clusters=4, max_iter=100, m=2, error=1e-6):
super().__init__()
self.u, self.centers, self.f = None, None, None
self.clusters_count = n_clusters
self.max_iter = max_iter
self.m = m
self.error = error
def fit(self, z):
N = z.shape[0]
C = self.clusters_count
centers = []
u = np.random.dirichlet(np.ones(N), size=C) iteration = 0
while iteration < self.max_iter:
u2 = u.copy()
centers = self.next_centers(z, u)
f = self._covariance(z, centers, u)
dist = self._distance(z, centers, f)
u = self.next_u(dist)
iteration += 1
# Stopping rule
if norm(u - u2) < self.error:
break
self.f = f
self.u = u
self.centers = centers
return centers
def gk_segment(img, clusters=5, smooth=False): # expand dims of binary image (1 channel in z axis)
new_img = np.expand_dims(img, axis=2)
# reshape
x, y, z = new_img.shape
new_img = new_img.reshape(x * y, z)
# segment using GK clustering
algorithm = GK(n_clusters=clusters)
cluster_centers = algorithm.fit(new_img)
output = algorithm.predict(new_img)
segments = cluster_centers[output].astype(np.int32).reshape(x,
y)
# get cluster that takes up least space (nodules / airway)
min_label = min_label_volume(segments)
segments[np.where(segments != min_label)] = 0
segments[np.where(segments == min_label)] = 1
return segments

Sekarang, mari kita segmentasikan hanya beberapa irisan (5 di antaranya) menggunakan kelas GK Clustering dan tampilkan salah satunya

# cluster slices (#324 - #328)
dist = 2
selected_slices = seg_lung_pixels[326-dist:326+(dist+1)]
gk_clustered_imgs = np.array([gk_segment(x) for x in
selected_slices])
# display middle slice (slice #326)
plt.imshow(gk_clustered_imgs[2], cmap=plt.cm.bone)
_

Struktur Internal Paru-paru

Hanya struktur internal. Agak keren ya?

Langkah 4. Teknik Visualisasi 2D

Tidak Interaktif

Saat memvisualisasikan data, menurut saya sangat bermanfaat untuk memvisualisasikan setiap proses skrip Anda. Ini tidak hanya akan membantu Anda memahami setiap langkah kode Anda, tetapi juga membuat presentasi yang sangat bagus dan bersih

Kode di bawah ini pada dasarnya akan menyampaikan cerita secara visual tentang bagaimana Anda menyegmentasikan data Anda. (1. ) gambar asli > (2. ) topeng biner yang menutupi paru > (3. ) menyoroti struktur internal paru-paru menggunakan salah satu topeng > (4. ) mengekstraksi struktur internal menggunakan pengelompokan GK

# pick random slice 
slice_id = 326
plt.figure(1)
plt.title('Original Dicom')
plt.imshow(patient_pixels[slice_id], cmap=plt.cm.bone)
plt.figure(2)
plt.title('Lung Mask')
plt.imshow(segmented_lungs_fill[slice_id], cmap=plt.cm.bone)
plt.figure(3)
plt.title('Parenchyma Mask on Segmented Lung')
plt.imshow(seg_lung_pixels[slice_id], cmap=plt.cm.bone)
plt.imshow(internal_structures[slice_id], cmap='jet', alpha=0.7)
plt.figure(4)
plt.title('Internal Structures Using GK Clustering')
plt.imshow(gk_segment_lung[2], cmap=plt.cm.bone)

Interaktif

Sebenarnya hanya ada beberapa cara untuk menampilkan banyak gambar di notebook jupyter — memplot setiap gambar secara manual satu per satu, atau membuat plot dengan beberapa kolom dan baris untuk ditampilkan dalam satu gambar. Sayangnya, ini tidak membantu bagi mereka yang ingin memindai setiap gambar dan mendapatkan pemahaman data yang lebih baik. Dengan kode di bawah ini Anda membuat bilah geser interaktif yang memungkinkan Anda menelusuri gambar

# slide through dicom images using a slide bar 
plt.figure(1)
def dicom_animation(x):
plt.imshow(original_dcm_pix[x])
return x
interact(dicom_animation, x=(0, len(original_dcm_pix)-1))
_

Langkah 5. Teknik Visualisasi 3D

Dalam pencitraan medis, biasanya menggunakan algoritme grafik komputer yang dikenal sebagai Marching Cubes untuk mengekstraksi permukaan dari data tiga dimensi. Dalam kasus kami, kami akan menggunakan pengukuran fungsi bawaan skimage. marching_cubes_lewiner

Non-interaktif

Apakah Anda menerapkan jaringan saraf convolutional 2D atau 3D ke dataset Anda, masih ada manfaat untuk melihat data DICOM Anda dalam 3D. Secara filosofis, jika Anda ingin algoritme Anda memiliki pemahaman yang baik tentang data agar bekerja seperti yang Anda inginkan — maka Anda juga harus memiliki pemahaman yang baik

def plot_3d(image):

# Position the scan upright,
# so the head of the patient would be at the top facing the
# camera
p = image.transpose(2,1,0)

verts, faces, _, _ = measure.marching_cubes_lewiner(p)
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
# Fancy indexing: `verts[faces]` to generate a collection of
# triangles
mesh = Poly3DCollection(verts[faces], alpha=0.70)
face_color = [0.45, 0.45, 0.75]
mesh.set_facecolor(face_color)
ax.add_collection3d(mesh)
ax.set_xlim(0, p.shape[0])
ax.set_ylim(0, p.shape[1])
ax.set_zlim(0, p.shape[2])
plt.show()# run visualization
plot_3d(internal_structures_mask)
_

Cukup keren ya?

Interaktif

Karena membuat plot 3D interaktif dapat memakan waktu (jika Anda memasukkan banyak data), sebaiknya gunakan ini saat Anda telah mengisolasi wilayah tertentu dari pemindaian Anda. Misalnya, mungkin Anda menemukan fitur abnormal dalam gambar Anda dan Anda ingin berinteraksi dengannya dalam 3D

Kode di bawah ini menunjukkan contoh memotong wilayah tertentu, mendapatkan irisan tetangga (sehingga kita dapat memperoleh beberapa pindaian 2D untuk membentuk volume 3D) dan memplotnya secara interaktif dalam 3D

def load_scan(path):
slices = [pydicom.dcmread(path + ‘/’ + s) for s in
os.listdir(path)]
slices = [s for s in slices if ‘SliceLocation’ in s]
slices.sort(key = lambda x: int(x.InstanceNumber))
try:
slice_thickness = np.abs(slices[0].ImagePositionPatient[2] —
slices[1].ImagePositionPatient[2])
except:
slice_thickness = np.abs(slices[0].SliceLocation —
slices[1].SliceLocation)
for s in slices:
s.SliceThickness = slice_thickness
return slices
def get_pixels_hu(scans):
image = np.stack([s.pixel_array for s in scans])
image = image.astype(np.int16)
# Set outside-of-scan pixels to 0
# The intercept is usually -1024, so air is approximately 0
image[image == -2000] = 0

# Convert to Hounsfield units (HU)
intercept = scans[0].RescaleIntercept
slope = scans[0].RescaleSlope

if slope != 1:
image = slope * image.astype(np.float64)
image = image.astype(np.int16)

image += np.int16(intercept)

return np.array(image, dtype=np.int16)
_0

Sekarang mari kita gunakan fungsi pembantu, bersama dengan gk_clustered_imgs untuk memangkas beberapa wilayah dan menampilkan tampilannya dalam 3D interaktif (di bawah ini hanya gambar, tetapi di buku catatan Anda, Anda dapat mengeklik dan memindahkannya, lol)

def load_scan(path):
slices = [pydicom.dcmread(path + ‘/’ + s) for s in
os.listdir(path)]
slices = [s for s in slices if ‘SliceLocation’ in s]
slices.sort(key = lambda x: int(x.InstanceNumber))
try:
slice_thickness = np.abs(slices[0].ImagePositionPatient[2] —
slices[1].ImagePositionPatient[2])
except:
slice_thickness = np.abs(slices[0].SliceLocation —
slices[1].SliceLocation)
for s in slices:
s.SliceThickness = slice_thickness
return slices
def get_pixels_hu(scans):
image = np.stack([s.pixel_array for s in scans])
image = image.astype(np.int16)
# Set outside-of-scan pixels to 0
# The intercept is usually -1024, so air is approximately 0
image[image == -2000] = 0

# Convert to Hounsfield units (HU)
intercept = scans[0].RescaleIntercept
slope = scans[0].RescaleSlope

if slope != 1:
image = slope * image.astype(np.float64)
image = image.astype(np.int16)

image += np.int16(intercept)

return np.array(image, dtype=np.int16)
_1

Kesimpulan

Sial ya. Anda baru saja memprogram kode paling non-non-NON-heinous yang melibatkan metode pengelompokan statistik, algoritme grafik komputer, dan pemrosesan gambar. Kami bahkan tidak perlu menggunakan kata-kata besar untuk membuatnya terdengar keren;)

Bagaimana cara membaca gambar DICOM dengan Python?

Ada beberapa opsi. .
Gunakan salah satu dari banyak program penampil DICOM yang tersedia
gunakan pydicom dengan matplotlib
gunakan pydicom dengan modul Tkinter stdlib Python
gunakan pydicom dengan Python Imaging Library (PIL)
gunakan pydicom dengan wxPython

Bagaimana cara membaca folder DICOM?

File DICOM adalah gambar yang berasal secara digital dari pemindaian medis, seperti MRI dan ultrasonografi. Anda dapat melihat file ini dengan penampil online gratis bernama Jack Image viewer di komputer mana pun . Jika Anda lebih suka aplikasi, Anda dapat mengunduh MicroDicom (khusus PC) atau membuka file di Adobe Photoshop (PC dan Mac).

Bagaimana cara menggunakan Pydicom dengan Python?

Panduan Pengguna pydicom
Cara menginstal pydicom. Instal rilis resmi. Instal menggunakan pip. Instal menggunakan conda. Mengunduh contoh/menguji file DICOM. Instal pustaka opsional. Memasang Bantal. Menginstal CharPyLS. Menginstal GDCM. Menginstal pylibjpeg. Instal versi pengembangan. .
Referensi API

Apa nama paket yang dapat Anda gunakan untuk membaca gambar DICOM dengan Python?

Untuk membaca file DICOM kami menggunakan paket pydicom dan untuk melihat hasilnya kami menggunakan matplotlib.