首页 > 其他分享 >pyqt5实现nii文件叠加显示

pyqt5实现nii文件叠加显示

时间:2024-10-29 16:49:37浏览次数:7  
标签:叠加 nii target self horizontalSlider pyqt5 ui ti data

        最近在做一个医学影像处理的项目,要求是使用pyqt5实现T1.nii文件和靶区文件的叠加显示。之前有web前端开发和一些python基础,pyqt5和医学影像文件(nii格式文件)处理都是第一次接触。趁着十一假期比较清闲,记录一下该功能实现的过程(pyqt5相关基础就不说了,B站很多新手教程)。

一、认识nii文件(包括如何使用python处理nii文件)

参考了如下文章

python 笔记:打开nii格式(nibabel 库)-CSDN博客

一文看懂如何用 Python 查看三维数据 (nii.gz格式) 的各种图像参数_.nii.gz-CSDN博客

【医学影像数据处理】nii 数据格式文件操作汇总_nii文件-CSDN博客

MRI脑影像分析——多种工具实现Nifti(*.nii)文件读取、处理与写入——把小舞写进脑海里、6mm半高全宽高斯核平滑脑影像、NIFTI文件合并、算fMRI平均图像_dpabi生成的nii怎嘛打开-CSDN博客

BraTs数据集处理及python读取.nii文件-CSDN博客

二、python实现T1.nii文件和靶区文件的叠加显示

在这部分,我直接面向人工智能编程,它提供了如下代码,尝试了可以运行,效果不错。

import nibabel as nib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

# 读取NIfTI文件
ti_img = nib.load('TI.nii')
target_img = nib.load('target.nii')

# 获取图像数据
ti_data = ti_img.get_fdata()
target_data = target_img.get_fdata()

# 确保两者数据形状相同
if ti_data.shape != target_data.shape:
    raise ValueError("两个NIfTI图像的形状不一致,请检查.")

# 图像维度
x_dim, y_dim, z_dim = ti_data.shape

# 创建图形和子图
fig, axs = plt.subplots(1, 3, figsize=(15, 5))

# 设置滑块位置
ax_slider_x = plt.axes([0.2, 0.01, 0.6, 0.03])  # X轴滑块
ax_slider_y = plt.axes([0.2, 0.05, 0.6, 0.03])  # Y轴滑块
ax_slider_z = plt.axes([0.2, 0.09, 0.6, 0.03])  # Z轴滑块

# 创建滑块
slider_x = Slider(ax_slider_x, 'X', 0, x_dim - 1, valinit=x_dim // 2, valstep=1)
slider_y = Slider(ax_slider_y, 'Y', 0, y_dim - 1, valinit=y_dim // 2, valstep=1)
slider_z = Slider(ax_slider_z, 'Z', 0, z_dim - 1, valinit=z_dim // 2, valstep=1)

# 用于更新显示函数
def update_images(val):
    x_idx = int(slider_x.val)
    y_idx = int(slider_y.val)
    z_idx = int(slider_z.val)

    # 清空子图,然后重绘
    for ax in axs:
        ax.clear()
    
    # 提取三个切片
    ti_slice_x = ti_data[x_idx, :, :]
    target_slice_x = target_data[x_idx, :, :]

    ti_slice_y = ti_data[:, y_idx, :]
    target_slice_y = target_data[:, y_idx, :]

    ti_slice_z = ti_data[:, :, z_idx]
    target_slice_z = target_data[:, :, z_idx]

    # 绘制剖面
    axs[0].imshow(ti_slice_x, cmap='gray', alpha=0.5)
    axs[0].imshow(target_slice_x, cmap='jet', alpha=0.5)
    axs[0].set_title(f'X Slice: {x_idx}')
    
    axs[1].imshow(ti_slice_y.T, cmap='gray', alpha=0.5)
    axs[1].imshow(target_slice_y.T, cmap='jet', alpha=0.5)
    axs[1].set_title(f'Y Slice: {y_idx}')
    
    axs[2].imshow(ti_slice_z.T, cmap='gray', alpha=0.5)
    axs[2].imshow(target_slice_z.T, cmap='jet', alpha=0.5)
    axs[2].set_title(f'Z Slice: {z_idx}')
    
    # 更新图像
    for ax in axs:
        ax.axis('off')
    
    plt.draw()

# 连接滑块与更新函数
slider_x.on_changed(update_images)
slider_y.on_changed(update_images)
slider_z.on_changed(update_images)

# 初次绘制
update_images(None)

plt.tight_layout()
plt.show()

 运行结果如下:

到现在为止,已经通过python实现了两个相同大小的nii文件的叠加显示。剩下的工作就是将上述功能集成到pyqt页面中显示。

三、在pyqt5页面中实现nii叠加功能(不另外弹出弹窗)

整体思路就是将上面的代码封装成几个函数,里面的数据替换成PYQT组件能读取和设置的值,然后绑定好组件和槽函数之间的调用关系即可。

1.默认加载T1图象

import nibabel as nib
import matplotlib.pyplot as plt
import pyqtgraph as pg
#默认加载T1图象
    def init_optional(self):
        global headModule_path
        ti_img = nib.load(headModule_path+'/T1.nii.gz')
        ti_data1 = ti_img.get_fdata()
        ti_data = np.flip(ti_data1, axis=1)  # 例如,翻转 X 轴

        self.ui.horizontalSlider.setMaximum(ti_data.shape[0])
        self.ui.horizontalSlider_2.setMaximum(ti_data.shape[1])
        self.ui.horizontalSlider_3.setMaximum(ti_data.shape[2])

        self.ui.horizontalSlider.setValue(round(ti_data.shape[0] / 2))
        self.ui.horizontalSlider_2.setValue(round(ti_data.shape[1] / 2))
        self.ui.horizontalSlider_3.setValue(round(ti_data.shape[2] / 2))

        # Set up matplotlib figure and canvas
        self.fig, self.axs = self.setup_matplotlib()
        self.canvas = FigureCanvas(self.fig)

        # Create horizontal layout in the central widget for the canvas
        layout = self.ui.verticalLayout_13
        layout.addWidget(self.canvas)  # Add the canvas to the layout
        self.update_images1(ti_data)
        self.ui.horizontalSlider.valueChanged.connect(lambda:self.update_images1(ti_data))
        self.ui.horizontalSlider_2.valueChanged.connect(lambda:self.update_images1(ti_data))
        self.ui.horizontalSlider_3.valueChanged.connect(lambda:self.update_images1(ti_data))
        plt.show()

2.setup_matplotlib函数

    def setup_matplotlib(self):
        # Create matplotlib figure and axes
        fig = Figure(figsize=(50,5))
        axs = [fig.add_subplot(2, 2, i + 1) for i in range(3)]
        fig.tight_layout()
        return fig, axs

3.update_images1函数

    def update_images1(self, ti_data):
        x_idx = self.ui.horizontalSlider.value()
        y_idx = self.ui.horizontalSlider_2.value()
        z_idx = self.ui.horizontalSlider_3.value()
        # Clear previous images
        for ax in self.axs:
            ax.clear()

        # Display slices
        self.axs[0].imshow(ti_data[x_idx, :, :], cmap='gray', alpha=0.5)
        self.axs[0].set_title(f'X Slice: {x_idx}')

        self.axs[1].imshow(ti_data[:, y_idx, :].T, cmap='gray', alpha=0.5)
        self.axs[1].set_title(f'Y Slice: {y_idx}')

        self.axs[2].imshow(ti_data[:, :, z_idx].T, cmap='gray', alpha=0.5)
        self.axs[2].set_title(f'Z Slice: {z_idx}')

        for ax in self.axs:
            ax.axis('off')
        self.canvas.draw()  # Refresh the canvas

4.选择需要叠加的nii文件(subject空间),进行叠加(update_images函数类似,不再重复了)

    def showpicture_subject(self):
        global headModule_path
        ti_img = nib.load(headModule_path + '/T1.nii.gz')
        target_img = nib.load(self.ui.label_46.text())
        ti_data1 = ti_img.get_fdata()
        target_data1 = target_img.get_fdata()

        ti_data = np.flip(ti_data1, axis=1)  # 例如,翻转 X 轴
        target_data = np.flip(target_data1, axis=1)  # 例如,翻转 X 轴

        if ti_data.shape != target_data.shape:
            raise ValueError("两个NIfTI图像的形状不一致,请检查.")
        print(ti_data.shape)
        print(target_data.shape)

        self.ui.horizontalSlider.setMaximum(ti_data.shape[0])
        self.ui.horizontalSlider_2.setMaximum(ti_data.shape[1])
        self.ui.horizontalSlider_3.setMaximum(ti_data.shape[2])

        self.ui.horizontalSlider.setValue(round(ti_data.shape[0]/2))
        self.ui.horizontalSlider_2.setValue(round(ti_data.shape[1]/2))
        self.ui.horizontalSlider_3.setValue(round(ti_data.shape[2]/2))

        self.update_images(ti_data,target_data)
        self.ui.horizontalSlider.valueChanged.connect(lambda:self.update_images(ti_data,target_data))
        self.ui.horizontalSlider_2.valueChanged.connect(lambda:self.update_images(ti_data,target_data))
        self.ui.horizontalSlider_3.valueChanged.connect(lambda:self.update_images(ti_data,target_data))
        #plt.tight_layout()
        plt.show()

5. 选择需要叠加的nii文件(MNI空间),进行叠加(update_images函数类似,不再重复了)

import SimpleITK as sitk
#叠加MNI空间靶区/靶网络nii文件时,调用此函数
    def showpicture_MNI(self):
        global headModule_path
        ti_img = sitk.ReadImage(headModule_path + '/MNI152_T1_1mm.nii.gz')  
        target_img = sitk.ReadImage(self.ui.label_46.text())
        t1_spacing = ti_img.GetSpacing()

        # 重采样分割图像,使其和 T1 图像大小一致
        resampler = sitk.ResampleImageFilter()
        resampler.SetSize(ti_img.GetSize())
        resampler.SetOutputSpacing(t1_spacing)
        resampler.SetOutputOrigin(ti_img.GetOrigin())
        resampler.SetOutputDirection(ti_img.GetDirection())
        resampler.SetDefaultPixelValue(0)  # 如果在重采样时出现空值,使用 0 填充

        # 使用线性插值进行重采样
        resampler.SetInterpolator(sitk.sitkNearestNeighbor)  # 分割图通常用邻近插值
        resampled_seg_image = resampler.Execute(target_img)

        # 将图像转换为 numpy 数组
        ti_data1 = sitk.GetArrayFromImage(ti_img)
        target_data1 = sitk.GetArrayFromImage(resampled_seg_image)
        ti_data = np.flip(ti_data1, axis=0)  # 例如,翻转 X 轴
        target_data = np.flip(target_data1, axis=0)  # 例如,翻转 X 轴
        self.ui.horizontalSlider.setMaximum(ti_data.shape[0])
        self.ui.horizontalSlider_2.setMaximum(ti_data.shape[1])
        self.ui.horizontalSlider_3.setMaximum(ti_data.shape[2])

        self.ui.horizontalSlider.setValue(round(ti_data.shape[0]/2))
        self.ui.horizontalSlider_2.setValue(round(ti_data.shape[1]/2))
        self.ui.horizontalSlider_3.setValue(round(ti_data.shape[2]/2))

        self.update_images(ti_data,target_data)
        self.ui.horizontalSlider.valueChanged.connect(lambda:self.update_images(ti_data,target_data))
        self.ui.horizontalSlider_2.valueChanged.connect(lambda:self.update_images(ti_data,target_data))
        self.ui.horizontalSlider_3.valueChanged.connect(lambda:self.update_images(ti_data,target_data))
        #plt.tight_layout()
        plt.show()

四、总结

在叠加两个nii图像时,发现python的nibabel库更简单易用,适合处理同在subject空间大小相同的nii文件(即两个nii文件的fdata.shape相同),但如果需要对大小不同的两个nii文件(同属MNI空间)图像的拉伸、重采样和插值等操作时,最好使用SimpleITK库,功能更完善。

标签:叠加,nii,target,self,horizontalSlider,pyqt5,ui,ti,data
From: https://blog.csdn.net/m0_50746196/article/details/142682646

相关文章

  • 基于YOLOv8深度学习的吸烟/抽烟行为检测系统【python源码+Pyqt5界面+数据集+训练代码
    背景及意义吸烟行为检测对于维护公共场所的健康环境、防止火灾事故的发生以及促进健康生活方式都具有重要作用。使用基于YOLOv8的吸烟行为检测系统能够有效识别视频中的吸烟行为,从而及时采取适当措施。本文基于YOLOv8深度学习框架,通过2357张图片,训练了一个进行吸烟行为的......
  • 基于YOLOv10/YOLOv9/YOLOv8深度学习的工业螺栓螺母检测系统【python源码+Pyqt5界面+数
    背景及意义工业螺栓螺母检测系统的实施显著提高了制造行业的产品质量和工作效率。该系统的应用涵盖了从生产、检查到包装等各个环节,为精密设备的维护和安全运行提供了强大的技术支持。本文基于YOLOv10/YOLOv9/YOLOv8深度学习框架,通过2548张工业螺栓螺母的相关图片,训练了可......
  • 基于YOLOv10/v9/v8深度学习的金属焊缝缺陷检测系统【python源码+Pyqt5界面+数据集+训
    背景及意义金属焊缝缺陷检测系统的实现显著提高了众多工业领域产品的安全性和可靠性。自动化的检测过程不仅增加了工作效率,还降低了人力成本和事故风险。本文基于YOLOv10/v9/v8深度学习框架,通过3170张金属焊缝缺陷的相关图片,训练了可进行焊缝缺陷目标检测的模型,可以分别......
  • 基于YOLOv8深度学习的人脸面部口罩检测系统【python源码+Pyqt5界面+数据集+训练代码】
    背景及意义人脸口罩面部检测能够准确地检测人脸是否佩戴口罩,对于控制疫情传播、保障公共卫生安全起到关键作用。本文基于YOLOv8深度学习框架,通过853张图片,训练了一个进行人脸面部口罩的目标检测模型,能够准确的检测人脸“戴口罩”、“未戴口罩”及“未正确佩戴口罩”。并基......
  • 用PyQt5中的textline实现log的实时显示
    在PyQt5中使用QLineEdit(即QTextLine的实现类之一)来实现日志的实时显示是可行的,但可能不适合大规模、多行日志的输出,因为QLineEdit仅支持单行文本。若要显示多行日志,建议使用QTextEdit,它更适合日志实时显示。但如果你确实希望使用QLineEdit来实现简单的日志输出,可以通......
  • 深度学习CNN算法狗类识别系统01-python带pyqt5界面数据集包配置
    项目基本介绍:【算法】深度学习CNN网络xception算法网络【环境】python=3.8pytorchopencvpyqt5matplotlib(含详细环境配置教程视频)【文件】训练、预测全部源代码、训练好的型、数据集、模型评价指标:训练acc/loss曲线图和混淆矩阵图、UI界面源码及源文件、环境配置教程视......
  • PyQt5 使用 Pyinstaller+multiprocessing 打包多进程应用时,引发的一些问题
    解决Pyinstaller打包PyQt5+multiprocessing多进程应用时,引发的一些问题,包括反复启动主进程,以及:AttributeError:'NoneType'objecthasnoattribute'write'本文提供一些解决方案,您可能需要根据自己的实际情况,逐个尝试,直到自己的multiprocessing多进程应用正常运行一、解决......
  • PyQt5开发环境搭建和配置
    PyQt5工具可以快速实现简单的界面开发,包括界面设计、布局管理以及业务逻辑实现(信号与槽)。简单说就是使用PyQt5工具可以快速画一个控件摆放整齐、界面整洁有序、布局合理的界面。课程目标可以动手实现简单的GUI程序。系列文章主要以动手实践案例讲解为主。课程对象会一些......
  • 【Python开发技术之PyQt5精品教学】第36课--PyQt5 拖放功能
    PyQt5拖放功能拖放功能对用户来说非常直观。它被应用于许多桌面应用程序,用户可以将对象从一个窗口复制或移动到另一个窗口。基于MIME的拖放数据传输是基于QDrag类实现的。QMimeData对象将数据与对应的MIME类型关联起来。数据被存储在剪贴板中,然后在拖放过程中使用。以下QMi......
  • 【Python开发技术之PyQt5精品教学】第32课--PyQt5 QDialog类
    PyQt5QDialog类QDialog 是一个顶层窗口小部件,主要用于收集用户的响应。它可以配置为 模态 (它会阻塞其父窗口)或 非模态 (对话框窗口可以被绕过)。PyQt API有许多预配置的对话框小部件,例如InputDialog,FileDialog,FontDialog等。示例在下面的示例中,对话框窗口的 WindowMo......