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

如何正确合成多帧DICOM?PNG转DICOM帧显示异常问题排查

多帧OCT图像转DICOM时帧重叠/裁剪问题解决

问题描述

将300余张连续PNG格式光学相干断层扫描(OCT)图像合成为多帧DICOM文件,已生成含375帧的文件,但帧图像出现重叠、裁剪,与原单帧PNG图像显示效果不符。

原代码

import os
import datetime
import numpy as np
import pydicom.encaps
from PIL import Image
from pydicom.dataset import FileMetaDataset, Dataset
from pydicom.uid import ExplicitVRLittleEndian


dt = datetime.datetime.now()

# Image folder and its contents
image_folder = r"E:\OCT\series_00\US000000"
image_files = [f for f in os.listdir(image_folder) if f.endswith('.png')]
image_files.sort()

# DICOM file metadata
file_meta = FileMetaDataset()
file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.14.1'  
file_meta.ImplementationClassUID = '1.2.3.4'

# Create a new multi-frame DICOM dataset
multi_frame_dataset = Dataset()
multi_frame_dataset.SOPClassUID = '1.2.840.10008.5.1.4.1.1.14.1'
multi_frame_dataset.PatientName = "Test^Name"
multi_frame_dataset.PatientID = "00-000-000"
multi_frame_dataset.ContentDate = dt.strftime('%Y%m%d')
multi_frame_dataset.ContentTime = dt.strftime('%H%M%S.%f')
multi_frame_dataset.is_little_endian = True
multi_frame_dataset.is_implicit_VR = False
multi_frame_dataset.SpecificCharacterSet = 'ISO_IR 100'

# List with 'pixel arrays' of all images (frames)
pixel_data = []

# Load and append each image to the pixel data list:
for image_file in image_files:
    image_path = os.path.join(image_folder, image_file)
    image = Image.open(image_path)
    pixel_array = np.array(image)
    pixel_data.append(pixel_array)

multi_frame_pixel_data = pydicom.encaps.encapsulate([frame.tobytes() for frame in pixel_data])

# Combine pixel data from all frames into the multi-frame DICOM
multi_frame_dataset.PixelData = multi_frame_pixel_data
multi_frame_dataset.Rows = pixel_data[0].shape[0]
multi_frame_dataset.Columns = pixel_data[0].shape[1]
multi_frame_dataset.NumberOfFrames = len(pixel_data)

# Set attributes for the multi-frame DICOM
multi_frame_dataset.SamplesPerPixel = 3
multi_frame_dataset.BitsAllocated = 8
multi_frame_dataset.BitsStored = 8
multi_frame_dataset.HighBit = 7
multi_frame_dataset.PixelRepresentation = 0

# Save the multi-frame DICOM file
save_path = r'C:\Desktop\New Folder\multi_frame.dcm'
multi_frame_dataset.save_as(save_path)

输出对比

  • 实际输出(帧重叠裁剪):
    实际输出
  • 预期输出(单帧原图像):
    预期输出

问题根源与修正方案

1. 通道格式不匹配

PNG图像默认可能为RGBA(4通道),但代码强制设置SamplesPerPixel = 3,导致像素数据长度不匹配,触发阅读器解析错误,需统一转换为RGB格式。

2. 缺少颜色空间定义

未设置PhotometricInterpretation属性,DICOM阅读器无法正确识别颜色空间,导致渲染异常,RGB图像需明确设置该属性为RGB。

3. 元数据不完整

未关联合法的SOP实例UID,且部分文件元数据未正确绑定到数据集,影响DICOM文件的合规性。

修正后的代码

import os
import datetime
import numpy as np
import pydicom.encaps
from PIL import Image
from pydicom.dataset import FileMetaDataset, Dataset
from pydicom.uid import ExplicitVRLittleEndian, generate_uid


dt = datetime.datetime.now()

# 图像文件夹路径
image_folder = r"E:\OCT\series_00\US000000"
image_files = [f for f in os.listdir(image_folder) if f.endswith('.png')]
image_files.sort()

# 文件元数据(必须正确关联到数据集)
file_meta = FileMetaDataset()
file_meta.MediaStorageSOPClassUID = '1.2.840.10008.5.1.4.1.1.14.1'  # OCT多帧SOP类
file_meta.MediaStorageSOPInstanceUID = generate_uid()
file_meta.ImplementationClassUID = '1.2.3.4'
file_meta.TransferSyntaxUID = ExplicitVRLittleEndian

# 创建多帧DICOM数据集
multi_frame_dataset = Dataset()
multi_frame_dataset.file_meta = file_meta
multi_frame_dataset.is_little_endian = True
multi_frame_dataset.is_implicit_VR = False
multi_frame_dataset.SOPClassUID = '1.2.840.10008.5.1.4.1.1.14.1'
multi_frame_dataset.SOPInstanceUID = file_meta.MediaStorageSOPInstanceUID
multi_frame_dataset.PatientName = "Test^Name"
multi_frame_dataset.PatientID = "00-000-000"
multi_frame_dataset.ContentDate = dt.strftime('%Y%m%d')
multi_frame_dataset.ContentTime = dt.strftime('%H%M%S.%f')
multi_frame_dataset.SpecificCharacterSet = 'ISO_IR 100'

# 处理每帧图像,统一转换为RGB格式
pixel_data = []
for image_file in image_files:
    image_path = os.path.join(image_folder, image_file)
    with Image.open(image_path) as img:
        # 转换为RGB,丢弃Alpha通道
        rgb_img = img.convert("RGB")
        pixel_array = np.array(rgb_img)
        # 确保像素数据内存布局符合DICOM要求
        pixel_array = np.ascontiguousarray(pixel_array)
        pixel_data.append(pixel_array)

# 封装多帧像素数据
multi_frame_pixel_data = pydicom.encaps.encapsulate([frame.tobytes() for frame in pixel_data])

# 设置像素相关属性
multi_frame_dataset.PixelData = multi_frame_pixel_data
multi_frame_dataset.Rows = pixel_data[0].shape[0]
multi_frame_dataset.Columns = pixel_data[0].shape[1]
multi_frame_dataset.NumberOfFrames = len(pixel_data)
multi_frame_dataset.SamplesPerPixel = 3
multi_frame_dataset.BitsAllocated = 8
multi_frame_dataset.BitsStored = 8
multi_frame_dataset.HighBit = 7
multi_frame_dataset.PixelRepresentation = 0
# 关键:添加颜色空间定义
multi_frame_dataset.PhotometricInterpretation = "RGB"

# 保存文件
save_path = r'C:\Desktop\New Folder\multi_frame.dcm'
multi_frame_dataset.save_as(save_path, write_like_original=False)

关键修改点说明

  • 强制将PNG图像转换为RGB格式,避免Alpha通道干扰
  • 添加PhotometricInterpretation = "RGB",明确颜色空间
  • 生成并关联合法的SOPInstanceUID,完善文件元数据
  • 使用np.ascontiguousarray确保像素数据内存布局符合DICOM要求
  • 保存时指定write_like_original=False,确保元数据正确写入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:22:17