如何读取多帧DICOM文件并在UI中直接显示为视频
直接在Tkinter中显示多帧DICOM(无需保存为GIF)
核心思路
- 用
pydicom读取多帧DICOM的原始像素数据 - 借助
PIL将DICOM像素数据转换为Tkinter支持的PhotoImage格式 - 利用Tkinter的
after()方法循环更新Label的图像,实现类视频的播放效果
完整代码示例
import tkinter as tk from pydicom import dcmread from pydicom.pixel_data_handlers.util import apply_voi_lut from PIL import Image, ImageTk import numpy as np def load_dicom_frames(dicom_path): """加载多帧DICOM并返回处理后的Tkinter图像列表""" ds = dcmread(dicom_path) # 获取多帧像素数据,shape为(帧数, 图像高度, 图像宽度) pixel_data = ds.pixel_array frames = [] for frame in pixel_data: # 应用窗宽窗位调整,还原医学影像的标准显示效果 img = apply_voi_lut(frame, ds) # 将非8位深度的像素数据归一化到0-255范围 if img.dtype != np.uint8: img = (img - img.min()) / (img.max() - img.min()) * 255 img = img.astype(np.uint8) # 转换为Tkinter可识别的图像格式 pil_img = Image.fromarray(img) tk_img = ImageTk.PhotoImage(pil_img) frames.append(tk_img) return frames if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="直接在Tkinter中播放多帧DICOM") parser.add_argument("dicom_image", help="目标DICOM文件的路径") args = parser.parse_args() root = tk.Tk() root.title("多帧DICOM播放器") # 加载并处理所有DICOM帧 dicom_frames = load_dicom_frames(args.dicom_image) frame_count = len(dicom_frames) # 创建用于显示图像的Label组件 label = tk.Label(root) label.pack() def update_frame(index): """循环更新显示的帧,实现播放效果""" current_frame = dicom_frames[index] label.config(image=current_frame) # 计算下一帧索引,实现循环播放 next_index = (index + 1) % frame_count # 每隔100ms更新一次,可根据需求调整播放速度 root.after(100, update_frame, next_index) # 启动播放 update_frame(0) root.mainloop()
关键细节说明
- 像素数据处理:DICOM像素常为16位深度,需归一化转8位,同时应用VOI LUT(窗宽窗位)保证医学影像的正确视觉呈现。
- 内存管理:必须用列表持有所有
PhotoImage对象,避免被Python垃圾回收机制清理,导致图像无法显示。 - 播放速度:调整
root.after()的时间参数(单位:毫秒)即可控制帧率,比如100ms对应10帧/秒。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

