DICOM(Digital Imaging and Communications in Medicine)
Dicom 文件的组成
主要包括两大部分:
-
文件头(Meta Information):
- 文件引言:每个DICOM文件开始部分包含一个固定长度的引言,通常是128字节,用于标识此文件为DICOM格式。
- Data Set(数据集)头信息:紧接着是四个字符组成的"DICM"字符串标识符,之后是一系列按照特定顺序排列的DICOM元素(Data Elements)。这些元数据包含了诸如病人ID、姓名、检查日期时间、设备信息、图像尺寸、像素大小、窗宽窗位、以及其他医学相关和成像参数等重要信息。
-
像素数据(Pixel Data):
- 这是DICOM文件的核心内容,包含了实际的二维或三维医学影像数据。像素数据可以是单幅或多幅(如CT切片或MRI序列)图像,并且根据不同的成像方式有不同的比特深度和编码方案(如8位灰度、16位灰度、24位彩色等)。
综上所述,它是一个综合了大量医学相关信息与图像数据的标准格式文件。
其中Dicom 数据集中的像素数据非常特别。它不能作为单个标签轻松读取或写入。
读取标签代码
var dcmFile = DicomFile.Open(path);
var dcmDataSet = dcmFile.Dataset;
string strPatientName = dcmDataSet.GetString(DicomTag.PatientName);
string strPatientSex = dcmDataSet.GetString(DicomTag.PatientSex);
//获取原始调窗
double datasetWinC = dcmDataSet.GetValue<double>(DicomTag.WindowCenter, 0);
double datasetWinW = dcmDataSet.GetValue<double>(DicomTag.WindowWidth, 0);
//获取宽高
int width = dcmDataSet.GetSingleValueOrDefault<int>(DicomTag.Columns, 0);
int height = dcmDataSet.GetSingleValueOrDefault<int>(DicomTag.Rows, 0);
// 获取 PixelSpacing
double[] pixelSpacing = dataset.Get<double[]>(DicomTag.PixelSpacing);
修改标签代码
string path=@"D:\Test.dcm";
var dcmFile = DicomFile.Open(path);
DicomDataset dataset = dcmFile.Dataset;
dataset.AddOrUpdate(DicomTag.SOPInstanceUID, CreateInstanceUID());
dataset.AddOrUpdate(DicomTag.ContentDate, CreateDateDICOMFormat(DateTime.Now));
dataset.AddOrUpdate(DicomTag.ContentTime, CreateTimeDICOMFormat(DateTime.Now));
dataset.AddOrUpdate(DicomTag.AcquisitionNumber, "00666");
dataset.AddOrUpdate(DicomTag.InstanceNumber, "00666");
dataset.AddOrUpdate(DicomTag.SamplesPerPixel, "3");
dataset.AddOrUpdate(DicomTag.PhotometricInterpretation, "RGB");
dataset.AddOrUpdate(DicomTag.BitsAllocated, "8");//实际存储的位数
dataset.AddOrUpdate(DicomTag.BitsStored, "8");//像素值的位数
dataset.AddOrUpdate(DicomTag.HighBit, "7");
dcmFile.Save(path);
修改dicom像素数据代码
DicomFile ctFile = DicomFile.Open(@"C:\Temp\original.dcm");
// Create PixelData object to represent pixel data in dataset
DicomPixelData pixelData = DicomPixelData.Create(ctFile.Dataset);
// Get Raw Data
byte[] originalRawBytes = pixelData.GetFrame(0).Data;
// Create new array with modified data
byte[] modifiedRawBytes = new byte[originalRawBytes.Length];
for (int i = 0; i < originalRawBytes.Length; i++)
{
modifiedRawBytes[i] = (byte)(originalRawBytes[i] + 100);
}
// Create new buffer supporting IByteBuffer to contain the modified data
MemoryByteBuffer modified = new MemoryByteBuffer(modifiedRawBytes);
// Write back modified pixel data
ctFile.Dataset.AddOrUpdatePixelData(DicomVR.OB, modified);
//保存为新更改数据
ctFile.Save(@"C:\Temp\Modified.dcm");
//保存回原路径
ctFile.Save(@"C:\Temp\original.dcm");
请注意,有更多的辅助类可以直接以特定格式处理像素数据,例如 PixelDataConverter
和 PixelDataFactory
。
此外,如果您想使用实际图像,请使用 DicomImage
类(class)。
关于c# - C#用fo-dicom对CT图像的PixelData进行处理和转换,
在Stack Overflow上找到一个类似的问题: type conversion - Manipulating and Converting PixelData of CT Image with fo-dicom in C# - Stack Overflow
读取dicom文件中的图像内容为Bitmap
对象
using Dicom;
using System.Drawing;
using System.Drawing.Imaging;
// 打开DICOM文件
DicomFile dicomFile = DicomFile.Open("path_to_your_dicom_file.dcm");
DicomDataset dataset = dicomFile.Dataset;
DicomPixelData pixelData = DicomPixelData.Create(dataset);
// 获取图像的基本信息,如宽度、高度、位深度等
int width = pixelData.Width;
int height = pixelData.Height;
int bitsPerPixel = pixelData.BitsAllocated;
// 创建合适的Bitmap格式
PixelFormat pixelFormat;
switch (bitsPerPixel)
{
case 8:
pixelFormat = PixelFormat.Format8bppIndexed;
break;
case 16:
pixelFormat = PixelFormat.Format16bppGrayScale;
break;
case 24:
pixelFormat = PixelFormat.Format24bppRgb;
break;
case 32:
pixelFormat = PixelFormat.Format32bppArgb;
break;
default:
throw new NotSupportedException($"不支持{bitsPerPixel}位/像素的图像格式");
}
// 创建Bitmap对象
Bitmap bitmap = new Bitmap(width, height, pixelFormat);
// 处理窗宽窗位和其他必要参数
// 对于非灰度图像,可能需要进行色彩映射表(LUT)应用或其他色彩空间转换
// 这里假设已经进行了必要的调整
// 将像素数据复制到Bitmap中
byte[] imageData = pixelData.GetFrame(0).ToArray();
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, pixelFormat);
IntPtr ptr = bitmapData.Scan0;
Marshal.Copy(imageData, 0, ptr, bitmapData.Stride * bitmap.Height);
bitmap.UnlockBits(bitmapData);
// 现在bitmap变量就包含了从DICOM图像转换而来的Bitmap对象
以上代码没有包括窗口级别和中心的校正,因为这通常需要依据DICOM元数据中的窗宽(WindowWidth)和窗位(WindowCenter)来进行调整,以及可能的颜色空间转换。在实际应用中,应当使用fo-dicom
提供的相关函数或手动计算来对原始像素值进行相应的线性或非线性变换。如果图像包含多个帧(对于CT或MR等多幅图像的情况),则需要遍历所有帧并重复上述过程。
参照链接:
c# - C#用fo-dicom对CT图像的PixelData进行处理和转换 - 代码先锋网
其他来源等。