当前位置: 首页 > java >正文

CT三视图显示及插值切片显示-全网独家(复制即用)

首先主题部分借鉴于下面大佬的代码

利用Python绘制 CT三视图 - 知乎

我在上述代码中优化了一部分插值切片,实现了功能:

显示两个切片之间的图像信息

1、import 头文件

import numpy as np
import pydicom
import os
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2

2、三个核心函数

def load_scan(path):temp = [pydicom.dcmread(path + f) for f in os.listdir(path)]slices = [t for t in temp if t.Modality == 'CT']# 修改排序方式,确保从下到上的正确顺序slices.sort(key=lambda x: -float(x.ImagePositionPatient[2]))  # 使用负号确保从下到上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 slicesdef get_pixels_hu(scans):image = np.stack([s.pixel_array for s in scans]) image = image.astype(np.int16)# Convert to Hounsfield units (HU)intercept = scans[0].RescaleInterceptslope = scans[0].RescaleSlopeif slope != 1:image = slope * image.astype(np.float64)image = image.astype(np.int16)image += np.int16(intercept)return np.array(image, dtype=np.int16)
def get_interpolated_slice(volume, position, axis=0):"""获取插值后的切片:param volume: 3D体数据:param position: 切片位置(浮点数):param axis: 插值轴 (0=axial, 1=coronal, 2=sagittal)"""# 获取相邻切片lower = int(np.floor(position))upper = int(np.ceil(position))# 边界检查lower = max(0, min(lower, volume.shape[axis]-1))upper = max(0, min(upper, volume.shape[axis]-1))# 线性插值if lower == upper:if axis == 0:return volume[lower, :, :]elif axis == 1:return volume[:, lower, :]else:return volume[:, :, lower]else:alpha = position - lowerif axis == 0:lower_slice = volume[lower, :, :]upper_slice = volume[upper, :, :]elif axis == 1:lower_slice = volume[:, lower, :]upper_slice = volume[:, upper, :]else:lower_slice = volume[:, :, lower]upper_slice = volume[:, :, upper]return (1-alpha)*lower_slice + alpha*upper_slice

3、图像采集与初始化参数

该部分进行小小的调整,原作者矢状面显示是横着的,我显示的是与3dslicer显示的一致

重点:

pydicom和3dslicer切片的顺序是正好相反的

dir_path_ct = r'C:\Desktop\ct_seg\dicom_data\\'
patient = load_scan(dir_path_ct)
imgs_ct = get_pixels_hu(patient)
# pixel aspects, assuming all slices are the same
ps = patient[0].PixelSpacing
ss = patient[0].SliceThickness
ax_aspect = ps[1]/ps[0]
sag_aspect = ss/ps[1]
cor_aspect = ss/ps[0]

注意:这里面的路径最后面要有斜杠,或者调整一下代码

4、显示插值切片(提供浮点数切片位置)

position = 255.5
interp_slice = get_interpolated_slice(imgs_ct, position, axis=1)# 归一化到0-255范围
interp_slice = cv2.normalize(interp_slice, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)# 计算显示窗口大小,保持正确比例
height, width = interp_slice.shape
aspect_ratio = ss/ps[0]  # 使用轴状面比例
height = int(height * aspect_ratio)# 调整图像大小保持比例
resized_img = cv2.resize(interp_slice, (width, height))
# 使用OpenCV显示
cv2.imshow('Interpolated Slice', resized_img)
cv2.waitKey(0)

5、显示三视图+插值切片

# 设置各视图的切片位置参数
# axial_slice = len(patient)//3    # 轴状面切片位置
axial_slice = 39
sagittal_slice = patient[0].pixel_array.shape[1]//2  # 矢状面切片位置
coronal_slice = patient[0].pixel_array.shape[0]//2   # 冠状面切片位置# plot 4 orthogonal slices
plt.figure(figsize=(12, 10))# 轴状面
a1 = plt.subplot(2, 2, 1)
plt.imshow(imgs_ct[axial_slice, :, :], cmap='gray')
a1.set_aspect(ax_aspect)
plt.title(f'Axial Slice {axial_slice}')# 矢状面
a2 = plt.subplot(2, 2, 2)
plt.imshow(imgs_ct[:,:,sagittal_slice], cmap='gray')
a2.set_aspect(sag_aspect)
plt.title(f'Sagittal Slice {sagittal_slice}')# 冠状面
a3 = plt.subplot(2, 2, 3)
plt.imshow(imgs_ct[:, coronal_slice, :], cmap='gray')
a3.set_aspect(cor_aspect)
plt.title(f'Coronal Slice {coronal_slice}')a4 = plt.subplot(2, 2, 4)
# 获取插值切片
position = 255
interp_slice = get_interpolated_slice(imgs_ct, position, axis=1)
# 归一化到0-255范围
interp_slice = cv2.normalize(interp_slice, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)plt.imshow(interp_slice, cmap='gray')
a4.set_aspect(sag_aspect)
plt.title(f'Interpolated Slice at {position}')plt.tight_layout(rect=[0, 0.03, 1, 0.9])
plt.show()

效果图显示

为了朋友的方便性,下面我插入完整代码

import numpy as np
import pydicom
import os
import matplotlib.pyplot as plt
from scipy import ndimage
import cv2def load_scan(path):temp = [pydicom.dcmread(path + f) for f in os.listdir(path)]slices = [t for t in temp if t.Modality == 'CT']# 修改排序方式,确保从下到上的正确顺序slices.sort(key=lambda x: -float(x.ImagePositionPatient[2]))  # 使用负号确保从下到上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 slicesdef get_pixels_hu(scans):image = np.stack([s.pixel_array for s in scans]) image = image.astype(np.int16)# Convert to Hounsfield units (HU)intercept = scans[0].RescaleInterceptslope = scans[0].RescaleSlopeif slope != 1:image = slope * image.astype(np.float64)image = image.astype(np.int16)image += np.int16(intercept)return np.array(image, dtype=np.int16)
def get_interpolated_slice(volume, position, axis=0):"""获取插值后的切片:param volume: 3D体数据:param position: 切片位置(浮点数):param axis: 插值轴 (0=axial, 1=coronal, 2=sagittal)"""# 获取相邻切片lower = int(np.floor(position))upper = int(np.ceil(position))# 边界检查lower = max(0, min(lower, volume.shape[axis]-1))upper = max(0, min(upper, volume.shape[axis]-1))# 线性插值if lower == upper:if axis == 0:return volume[lower, :, :]elif axis == 1:return volume[:, lower, :]else:return volume[:, :, lower]else:alpha = position - lowerif axis == 0:lower_slice = volume[lower, :, :]upper_slice = volume[upper, :, :]elif axis == 1:lower_slice = volume[:, lower, :]upper_slice = volume[:, upper, :]else:lower_slice = volume[:, :, lower]upper_slice = volume[:, :, upper]return (1-alpha)*lower_slice + alpha*upper_slice# open CT_lung dataset
dir_path_ct = r'D:\DICOM1\\'
patient = load_scan(dir_path_ct)
imgs_ct = get_pixels_hu(patient)
# pixel aspects, assuming all slices are the same
ps = patient[0].PixelSpacing
ss = patient[0].SliceThickness
print(ps, ss)
ax_aspect = ps[1]/ps[0]
sag_aspect = ss/ps[1]
cor_aspect = ss/ps[0]# 设置各视图的切片位置参数
# axial_slice = len(patient)//3    # 轴状面切片位置
axial_slice = 39
sagittal_slice = patient[0].pixel_array.shape[1]//2  # 矢状面切片位置
coronal_slice = patient[0].pixel_array.shape[0]//2   # 冠状面切片位置# plot 4 orthogonal slices
plt.figure(figsize=(12, 10))# 轴状面
a1 = plt.subplot(2, 2, 1)
plt.imshow(imgs_ct[axial_slice, :, :], cmap='gray')
a1.set_aspect(ax_aspect)
plt.title(f'Axial Slice {axial_slice}')# 矢状面
a2 = plt.subplot(2, 2, 2)
plt.imshow(imgs_ct[:,:,sagittal_slice], cmap='gray')
a2.set_aspect(sag_aspect)
plt.title(f'Sagittal Slice {sagittal_slice}')# 冠状面
a3 = plt.subplot(2, 2, 3)
plt.imshow(imgs_ct[:, coronal_slice, :], cmap='gray')
a3.set_aspect(cor_aspect)
plt.title(f'Coronal Slice {coronal_slice}')a4 = plt.subplot(2, 2, 4)
# 获取插值切片
position = 255
interp_slice = get_interpolated_slice(imgs_ct, position, axis=1)
# 归一化到0-255范围
interp_slice = cv2.normalize(interp_slice, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)plt.imshow(interp_slice, cmap='gray')
a4.set_aspect(sag_aspect)
plt.title(f'Interpolated Slice at {position}')plt.tight_layout(rect=[0, 0.03, 1, 0.9])
plt.show()

如果有相关问题,可以关注,发私信,希望找到志同道合的朋友们!

http://www.xdnf.cn/news/1919.html

相关文章:

  • react和vue的区别之一
  • 常见的6种外挂获取执行时机方法介绍
  • OpenAI 推出「轻量级」Deep Research,免费用户同享
  • Python 基础语法与数据类型(四) - 布尔类型 (bool) 与逻辑运算符 (and, or, not) 和类型转换
  • ctfshow web入门 命令执行(29-77)
  • 智能分析网关摄像机实时接入分析平台,如何开启周界防护智能新时代?
  • 中小企业固定资产管理挑战与数字化破局之道
  • 轻量化AIGC边缘部署实战:在移动端实现实时AI内容生成
  • 身份与访问管理(IAM):零信任架构下的认证授权技术与实战
  • 终端运行java出现???
  • vite+vue2+elementui构建之 vite.config.js
  • 今日行情明日机会——20250425
  • 如何优化字符串替换:四种实现方案对比与性能分析
  • 自学新标日第二十二课(复习)
  • ViewPager FragmentPagerAdapter在系统杀死应用后重建时UI不刷新的问题
  • Hadoop生态圈框架部署 - Windows上部署Hadoop
  • MySQL锁
  • redis客户端库redis++在嵌入式Linux下的交叉编译及使用
  • 从线性到非线性:简单聊聊神经网络的常见三大激活函数
  • 不吃【Numpy】版
  • Spring AI 快速入门:从环境搭建到核心组件集成
  • 高精度运算
  • 有关虚拟奢侈品
  • Java知识日常巩固(四)
  • Linux Ubuntu18.04下安装Qt Craeator 5.12.9(图文详解)
  • 【Qt】文件
  • 探秘LLM推理模型:hidden states中藏着的self verification的“钥匙”
  • PubMed PDF下载 cloudpmc-viewer-pow逆向
  • C#中实现XML解析器
  • YOLOX-PAI手部检测模型