DCM转Raw遇‘bytes无法隐式转str’错误及MHD文件生成咨询
解决DCM转Raw的类型错误 & 生成MHD文件方案
一、先搞定Can't convert 'bytes' object to str implicitly错误
你遇到这个问题的核心原因很简单:字符串和字节类型不能直接拼接。
看你的代码,你初始化allInOne = ""(这是字符串类型),但dataset.PixelData是字节(bytes)类型,用+=拼接时Python就会报错。你尝试用encode("utf-8")完全没用,因为空字符串编码后还是空字节,反而把原本的拼接逻辑搞乱了。
修复方法:
- 把
allInOne的初始值改成字节空对象b"",这样后续拼接字节数据就完全匹配了 - 你的路径拼接方式
dicomPath + "".join(filename)有坑——如果遍历到子目录里的DICOM文件,这个路径会找不到文件,建议用os.path.join(dirName, filename)来自动处理路径分隔符 numpy里的tostring()已经被废弃了,推荐用tobytes()替代
修改后的核心循环代码:
for dirName, subdirList, fileList in os.walk(dicomPath): allInOne = b"" # 关键:改为字节类型初始值 print(subdirList) i=0 for filename in fileList: i+=1 if filename.endswith((".dcm", ".DCM")): # 正确拼接路径 path = os.path.join(dirName, filename) dataset = dicom.read_file(path) # 像素值处理逻辑保留 for n,val in enumerate(dataset.pixel_array.flat): dataset.pixel_array.flat[n] = val / 60 if val < 0: dataset.pixel_array.flat[n] = 0 # 用tobytes()替代tostring() dataset.PixelData = numpy.uint8(dataset.pixel_array).tobytes() # 现在可以正常拼接字节数据了 allInOne += dataset.PixelData print(f"slice {filename} done {i}") # 用f-string更简洁直观
二、生成对应的MHD文件
MHD文件是Raw数据的“描述文件”,它告诉读取工具Raw数据的维度、像素类型、间距等信息。下面是适配你Raw生成逻辑的MHD生成代码:
完整的MHD生成函数
import dicom import os import numpy as np def generate_mhd(raw_file_path, mhd_file_path, dicom_root_path): # 先获取第一个DICOM文件的元信息(作为序列基准) first_dcm = None total_slices = 0 # 遍历统计切片数量并获取第一个DICOM文件 for dirpath, _, filenames in os.walk(dicom_root_path): for fname in filenames: if fname.lower().endswith(".dcm"): total_slices += 1 if not first_dcm: first_dcm = dicom.read_file(os.path.join(dirpath, fname)) if first_dcm: break if not first_dcm: print("Error: No DICOM files found in the path!") return # 从DICOM中提取关键参数 img_width = first_dcm.Columns img_height = first_dcm.Rows pixel_spacing = first_dcm.PixelSpacing # 如果DICOM没有SliceThickness字段,默认用像素间距的第一个值替代 slice_thickness = first_dcm.SliceThickness if hasattr(first_dcm, "SliceThickness") else pixel_spacing[0] # MHD文件的内容模板,注意ElementType要和你转换的像素类型匹配(这里是uint8,对应MET_UCHAR) mhd_content = f"""ObjectType = Image NDims = 3 BinaryData = True BinaryDataByteOrderMSB = False CompressedData = False TransformMatrix = 1 0 0 0 1 0 0 0 1 Offset = 0 0 0 CenterOfRotation = 0 0 0 ElementSpacing = {pixel_spacing[0]} {pixel_spacing[1]} {slice_thickness} DimSize = {img_width} {img_height} {total_slices} ElementType = MET_UCHAR ElementDataFile = {os.path.basename(raw_file_path)} """ # 写入MHD文件 with open(mhd_file_path, "w", encoding="utf-8") as f: f.write(mhd_content) print(f"Successfully generated MHD file: {mhd_file_path}")
调用方式
在你生成Raw文件之后,直接调用这个函数即可:
# 生成Raw文件的代码执行完后 generate_mhd("./all_in_one.raw", "./all_in_one.mhd", dicomPath)
整合后的完整代码
把两部分整合起来,就是可以直接运行的完整脚本了:
import dicom import os import numpy as np import sys dicomPath = "C:/DataLuna16pen/dcmdata/" def generate_mhd(raw_file_path, mhd_file_path, dicom_root_path): first_dcm = None total_slices = 0 for dirpath, _, filenames in os.walk(dicom_root_path): for fname in filenames: if fname.lower().endswith(".dcm"): total_slices += 1 if not first_dcm: first_dcm = dicom.read_file(os.path.join(dirpath, fname)) if first_dcm: break if not first_dcm: print("Error: No DICOM files found!") return img_width = first_dcm.Columns img_height = first_dcm.Rows pixel_spacing = first_dcm.PixelSpacing slice_thickness = first_dcm.SliceThickness if hasattr(first_dcm, "SliceThickness") else pixel_spacing[0] mhd_content = f"""ObjectType = Image NDims = 3 BinaryData = True BinaryDataByteOrderMSB = False CompressedData = False TransformMatrix = 1 0 0 0 1 0 0 0 1 Offset = 0 0 0 CenterOfRotation = 0 0 0 ElementSpacing = {pixel_spacing[0]} {pixel_spacing[1]} {slice_thickness} DimSize = {img_width} {img_height} {total_slices} ElementType = MET_UCHAR ElementDataFile = {os.path.basename(raw_file_path)} """ with open(mhd_file_path, "w", encoding="utf-8") as f: f.write(mhd_content) print(f"MHD file generated: {mhd_file_path}") # 处理DICOM并生成Raw文件 allInOne = b"" for dirName, subdirList, fileList in os.walk(dicomPath): i = 0 for filename in fileList: i += 1 if filename.lower().endswith(".dcm"): path = os.path.join(dirName, filename) try: dataset = dicom.read_file(path) # 像素值归一化与截断 for n, val in enumerate(dataset.pixel_array.flat): normalized_val = val / 60 dataset.pixel_array.flat[n] = max(0, normalized_val) # 转换为uint8字节数据 dataset.PixelData = np.uint8(dataset.pixel_array).tobytes() allInOne += dataset.PixelData print(f"Processed slice: {filename} ({i})") except Exception as e: print(f"Failed to process {filename}: {str(e)}") # 写入Raw文件 with open("./all_in_one.raw", "wb") as raw_file: raw_file.write(allInOne) print("RAW file generated successfully!") # 生成对应的MHD文件 generate_mhd("./all_in_one.raw", "./all_in_one.mhd", dicomPath)
内容的提问来源于stack exchange,提问作者黃本聰
相关产品推荐
相关产品推荐

