Java中如何为DICOM文件添加元数据?JPG转DICOM代码存问题
解决Java生成DICOM时的必填元数据问题
嘿,我明白你在从JPG生成DICOM文件时遇到的必填标签难题了——DICOM标准确实有一堆必须填的元数据,漏一个都不行。我帮你梳理一下必须补充的内容,再给你完整点的代码示例:
一、文件元信息(File Meta)必须补充的标签
你已经加了FileMetaInformationGroupLength和TransferSyntaxUID,但还缺这几个核心项:
MediaStorageSOPClassUID:指定DICOM图像的SOP类,普通JPG转DICOM用Secondary Capture Image Storage(1.2.840.10008.5.1.4.1.1.104.1)最合适MediaStorageSOPInstanceUID:每个DICOM文件唯一的实例ID,得生成一个符合DICOM格式的唯一值(可以用UUID转或者用工具类生成)ImplementationClassUID:你的程序实现的专属UID,自定义一个比如1.2.3.4.5.6.7.8就行,只要符合UID格式ImplementationVersionName:你的程序版本标识,比如MyDicomConverter_v1.0
二、DICOM数据集(Dataset)的核心必填标签
除了StudyDate、StudyTime,还得覆盖这几类关键标签:
1. 患者基础信息
PatientName:患者姓名(必填,哪怕填匿名的^Anonymous^)PatientID:患者唯一标识IDPatientBirthDate:患者生日(可以填空,但建议按YYYYMMDD格式填写)
2. 检查/序列/实例信息
StudyInstanceUID:检查唯一ID(和SOP实例ID一样,需唯一)SeriesInstanceUID:序列唯一IDSOPInstanceUID:要和文件元里的保持一致Modality:成像模态,JPG转的填SC(Secondary Capture)就行StudyDescription:检查内容描述
3. 图像属性(从JPG转的话这些是核心)
Rows/Columns:对应JPG的高度和宽度BitsAllocated/BitsStored:JPG一般都是8位,所以填8HighBit:最高位,8位像素填7(从0开始计数)PixelRepresentation:0代表无符号像素(JPG用这个)PhotometricInterpretation:RGB图填RGB,灰度图填MONOCHROME2PixelData:把JPG的像素数据转成DICOM要求的字节数组格式
三、完整代码示例(基于dcm4che库)
import org.dcm4che3.data.Attributes; import org.dcm4che3.data.Tag; import org.dcm4che3.data.VR; import org.dcm4che3.io.DicomOutputStream; import org.dcm4che3.util.UIDUtils; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; public class JpgToDicomConverter { public static void main(String[] args) throws IOException { // 1. 读取目标JPG图片 BufferedImage jpgImage = ImageIO.read(new File("input.jpg")); int imgWidth = jpgImage.getWidth(); int imgHeight = jpgImage.getHeight(); // 2. 生成唯一DICOM UID(用dcm4che工具类更省心) String studyUID = UIDUtils.createUID(); String seriesUID = UIDUtils.createUID(); String sopInstanceUID = UIDUtils.createUID(); // 3. 构建文件元信息 Attributes fileMeta = new Attributes(); fileMeta.setInt(Tag.FileMetaInformationGroupLength, VR.UL, 0); // 后续会自动计算,先填0 fileMeta.setString(Tag.MediaStorageSOPClassUID, VR.UI, "1.2.840.10008.5.1.4.1.1.104.1"); fileMeta.setString(Tag.MediaStorageSOPInstanceUID, VR.UI, sopInstanceUID); fileMeta.setString(Tag.TransferSyntaxUID, VR.UI, "1.2.840.10008.1.2.1"); // 显式小端字节序 fileMeta.setString(Tag.ImplementationClassUID, VR.UI, "1.2.3.4.5.6.7.8"); fileMeta.setString(Tag.ImplementationVersionName, VR.SH, "Jpg2Dicom_v1.0"); // 4. 构建DICOM数据集 Attributes dataset = new Attributes(); // 患者信息 dataset.setString(Tag.PatientName, VR.PN, "^Anonymous^"); dataset.setString(Tag.PatientID, VR.LO, "PAT_0001"); dataset.setString(Tag.PatientBirthDate, VR.DA, ""); // 检查/序列/实例信息 dataset.setString(Tag.StudyInstanceUID, VR.UI, studyUID); dataset.setString(Tag.SeriesInstanceUID, VR.UI, seriesUID); dataset.setString(Tag.SOPInstanceUID, VR.UI, sopInstanceUID); dataset.setString(Tag.Modality, VR.CS, "SC"); dataset.setString(Tag.StudyDate, VR.DA, "20110404"); dataset.setString(Tag.StudyTime, VR.TM, "150000"); // 注意格式必须是HHMMSS,之前的"15"不符合标准 dataset.setString(Tag.StudyDescription, VR.LO, "JPG转DICOM示例"); // 图像属性 dataset.setInt(Tag.Rows, VR.US, imgHeight); dataset.setInt(Tag.Columns, VR.US, imgWidth); dataset.setInt(Tag.BitsAllocated, VR.US, 8); dataset.setInt(Tag.BitsStored, VR.US, 8); dataset.setInt(Tag.HighBit, VR.US, 7); dataset.setInt(Tag.PixelRepresentation, VR.US, 0); dataset.setString(Tag.PhotometricInterpretation, VR.CS, "RGB"); dataset.setInt(Tag.SamplesPerPixel, VR.US, 3); // RGB是3通道 dataset.setInt(Tag.PixelSpacing, VR.DS, new float[]{1.0f, 1.0f}); // 像素间距,按需调整 // 处理像素数据:把BufferedImage转成DICOM要求的字节数组 ByteBuffer pixelBuffer = ByteBuffer.allocate(imgWidth * imgHeight * 3); for (int y = 0; y < imgHeight; y++) { for (int x = 0; x < imgWidth; x++) { int rgb = jpgImage.getRGB(x, y); pixelBuffer.put((byte) ((rgb >> 16) & 0xFF)); // R通道 pixelBuffer.put((byte) ((rgb >> 8) & 0xFF)); // G通道 pixelBuffer.put((byte) (rgb & 0xFF)); // B通道 } } dataset.setBytes(Tag.PixelData, VR.OW, pixelBuffer.array()); // 5. 写入DICOM文件 try (DicomOutputStream dos = new DicomOutputStream(new FileOutputStream("output.dcm"))) { dos.writeFileMetaInformation(fileMeta); dos.writeDataset(fileMeta.getString(Tag.TransferSyntaxUID, VR.UI), dataset); } } }
几个关键提醒
- 时间格式要合规:
StudyTime必须是HHMMSS或HHMMSS.ffffff,你之前写的"15"不符合标准,会导致DICOM验证失败 - UID要唯一:用
UIDUtils.createUID()生成最省心,避免手动拼接出错 - 像素数据要对应:如果是灰度JPG,记得把
SamplesPerPixel改成1,PhotometricInterpretation改成MONOCHROME2 - 验证工具:生成文件后可以用dcmtk的
dcmdump或者Weasis打开检查,确认没有缺失必填标签
内容的提问来源于stack exchange,提问作者celia
相关产品推荐
相关产品推荐

