You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用pydicom将多张JPG图像生成DICOM文件并修复像素数组问题

多帧DICOM生成代码修正方案

核心问题修复点

  • 像素数组拼接逻辑错误:原代码直接将多个单帧字节数组转为numpy数组赋值给PixelData,多帧DICOM要求所有帧的像素字节按顺序拼接为单个连续字节流
  • 单帧残留配置未更新:ImagesInAcquisition、ImagePositionPatient等标签仍为单图参数,多帧场景下需要适配调整
  • 缺少输入校验:未校验所有输入图像的宽高一致性,易引发DICOM解析异常

修正后完整代码

import pydicom
from pydicom.dataset import Dataset
from PIL import Image
import numpy as np
from os import walk

# 自然排序函数(原代码未给出,补充实现)
def natural_keys(text):
    import re
    return [int(c) if c.isdigit() else c for c in re.split(r'(\d+)', text)]

# Populate required values for file meta information
meta = pydicom.Dataset()
meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian
meta.MediaStorageSOPClassUID = pydicom._storage_sopclass_uids.MRImageStorage
meta.MediaStorageSOPInstanceUID = pydicom.uid.generate_uid()

# build dataset
ds = Dataset()
ds.file_meta = meta
ds.fix_meta_info()

# 通用DICOM配置
ds.is_little_endian = True
ds.is_implicit_VR = False
ds.SOPClassUID = pydicom._storage_sopclass_uids.MRImageStorage
ds.SeriesInstanceUID = pydicom.uid.generate_uid()
ds.StudyInstanceUID = pydicom.uid.generate_uid()
ds.FrameOfReferenceUID = pydicom.uid.generate_uid()
ds.ImageOrientationPatient = r"1\0\0\0\-1\0"
ds.ImageType = r"ORIGINAL\PRIMARY\AXIAL"
ds.RescaleIntercept = "0"
ds.RescaleSlope = "1"

# 病例信息配置
ds.PatientName = "Anonymous"
ds.PatientID = "123456"
ds.Modality = "MR"
ds.StudyDate = '20200225'
ds.ContentDate = '20200225'

def ensure_even(stream):
    # 适配部分DICOM查看器要求,字节流长度必须为偶数
    if len(stream) % 2:
        return stream + b"\x00"
    return stream

pixel_data_list = []
img_width = None
img_height = None

for root, dir, filenames in walk(folder):
    filenames.sort(key=natural_keys)
    for filename in filenames:
        full_path = folder + filename
        # 转灰度图
        img = Image.open(full_path).convert('L')
        # 校验所有图像尺寸一致
        if img_width is None:
            img_width = img.width
            img_height = img.height
        else:
            if img.width != img_width or img.height != img_height:
                raise ValueError(f"输入图像{filename}尺寸与首图不一致,无法拼接多帧DICOM")
        # 转为numpy数组
        arr = np.array(img)
        pixel_data_list.append(arr.tobytes())

# 8位灰度图配置
ds.BitsStored = 8
ds.BitsAllocated = 8
ds.HighBit = 7
ds.PixelRepresentation = 0
ds.PhotometricInterpretation = "MONOCHROME2"
ds.SamplesPerPixel = 1
ds.file_meta.TransferSyntaxUID = pydicom.uid.ExplicitVRLittleEndian

# 多帧配置
frame_count = len(pixel_data_list)
ds.NumberOfFrames = frame_count
ds.ImagesInAcquisition = str(frame_count)
# 拼接所有帧的像素字节流
ds.PixelData = b''.join([ensure_even(frame) for frame in pixel_data_list])

# 图像尺寸配置
ds['PixelData'].is_undefined_length = False
ds.Columns = img_width
ds.Rows = img_height

# 校验保存
pydicom.dataset.validate_file_meta(ds.file_meta, enforce_standard=True)
new_filename = f"{name}.dcm"
ds.save_as(new_filename, write_like_original=False)

低优先级问题解决思路(压缩/彩色模式)

  • 压缩功能:安装pylibjpeg及对应编码插件,将TransferSyntaxUID修改为对应压缩语法,再通过pydicom的压缩接口处理像素数据即可
  • 彩色模式:将PhotometricInterpretation改为RGB,SamplesPerPixel改为3,PlanarConfiguration设为0,输入图像不做灰度转换直接提取RGB通道数组拼接即可

内容的提问来源于stack exchange,提问作者Johann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 08:57:03