C# Jpg、Bmp图像转Dicom

发布时间 2023-06-28 14:23:58作者: 业荒于嬉

什么是Dicom?

DICOM(Digital Imaging and Communications in Medicine)即医学数字成像和通信,是医学图像和相关信息的国际标准(ISO 12052)。它定义了质量能满足临床需要的可用于数据交换的医学图像格式。

使用Dicom有什么优势?

DICOM标准的推出与实现,大大简化了医学影像信息交换的实现,推动了远程放射学系统、图像管理与通信系统(PACS)的研究与发展,并且由于DICOM的开放性与互联性,使得与其它医学应用系统(HIS、RIS等)的集成成为可能。此处,Dicom标注还定义了数据集,数据集又由多个数据元素(Data Element)组成,每个数据元素描述一条信息,因此可以在Dicom文件中存储一些数据,例如患者信息、申请单信息、检查类型等。

源代码展示

  1     public class ConverttHelper
  2     {
  3         public static void ImageFileToDicomFile(DicomUploadImageInfo dicomUploadImageInfo, DicomUploadInfo dicomInfo, DicomUID studyUID, DicomUID seriesUID, DicomUID imageUID)
  4         {
  5             using (var bitmap = new Bitmap(dicomUploadImageInfo.ImageFileName))
  6             {
  7                 int rows, columns;
  8                 byte[] pixels;
  9                 if (bitmap.PixelFormat != PixelFormat.Format24bppRgb)
 10                 {
 11                     using (var newBitmap = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format24bppRgb))
 12                     {
 13                         using (var g = Graphics.FromImage(newBitmap))
 14                         {
 15                             g.DrawImage(bitmap, 0, 0, bitmap.Width, bitmap.Height);
 16                         }
 17                         pixels = GetPixels(newBitmap, out rows, out columns);
 18                     }
 19                 }
 20                 else
 21                 {
 22                     pixels = GetPixels(bitmap, out rows, out columns);
 23                 }
 24                 var buffer = new MemoryByteBuffer(pixels);
 25                 var dataset = new DicomDataset();
 26                 FillDataset(dataset, dicomInfo, dicomUploadImageInfo, studyUID, seriesUID, imageUID);
 27                 dataset.Add(DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value);
 28                 dataset.Add(DicomTag.Rows, (ushort)rows);
 29                 dataset.Add(DicomTag.Columns, (ushort)columns);
 30                 dataset.Add(DicomTag.BitsAllocated, (ushort)8);
 31                 var pixelData = DicomPixelData.Create(dataset, true);
 32                 pixelData.BitsStored = 8;
 33                 pixelData.SamplesPerPixel = 3;
 34                 pixelData.HighBit = 7;
 35                 pixelData.PixelRepresentation = 0;
 36                 pixelData.PlanarConfiguration = 0;
 37                 pixelData.AddFrame(buffer);
 38                 var dicomFile = new DicomFile(dataset);
 39                 if (_imageCompression)
 40                 {
 41                     try
 42                     {
 43                         // 压缩方式存储
 44                         DicomTranscoder transcoder = new DicomTranscoder(dicomFile.Dataset.InternalTransferSyntax, DicomTransferSyntax.JPEGLSLossless);
 45                         transcoder.Transcode(dicomFile).Save(dicomUploadImageInfo.TargetFileName);
 46                     }
 47                     catch
 48                     {
 49                         // 压缩失败,则改为不压缩的方式存储
 50                         dicomFile.Save(dicomUploadImageInfo.TargetFileName);
 51                     }
 52                 }
 53                 else
 54                 {
 55                     dicomFile.Save(dicomUploadImageInfo.TargetFileName);
 56                 }
 57             }
 58         }
 59 
 60         private static void FillDataset(DicomDataset dataset, DicomUploadInfo dicomInfo, DicomUploadImageInfo dicomUploadImageInfo, DicomUID studyUID, DicomUID seriesUID, DicomUID imageUID)
 61         {
 62             // Type 1 attributes
 63             dataset.Add(DicomTag.SOPClassUID, dicomUploadImageInfo.Modality == "ES" ? DicomUID.VideoEndoscopicImageStorage : DicomUID.UltrasoundImageStorage);
 64             dataset.Add(DicomTag.StudyInstanceUID, studyUID);
 65             dataset.Add(DicomTag.SeriesInstanceUID, seriesUID);
 66             dataset.Add(DicomTag.SOPInstanceUID, imageUID);
 67 
 68             // Type 2 attributes
 69             dataset.Add(DicomTag.PatientID, dicomInfo.PatientId);
 70             dataset.Add(DicomTag.PatientName, dicomInfo.PatientName);
 71             dataset.Add(DicomTag.PatientSex, dicomInfo.PatientGender);
 72             dataset.Add(DicomTag.PatientBirthDate, dicomInfo.PatientDob);
 73             dataset.Add(DicomTag.StudyDate, dicomInfo.StudyTime.Date);
 74             dataset.Add(DicomTag.StudyTime, dicomInfo.StudyTime);
 75             dataset.Add(DicomTag.AccessionNumber, dicomInfo.AccessionNumber);
 76             dataset.Add(DicomTag.StudyID, "1");
 77             dataset.Add(DicomTag.SeriesNumber, "100");
 78             dataset.Add(DicomTag.Modality, dicomUploadImageInfo.Modality);
 79             if (!string.IsNullOrWhiteSpace(dicomUploadImageInfo.PixelSpacing))
 80             {
 81                 dataset.Add(DicomTag.PixelSpacing, dicomUploadImageInfo.PixelSpacing);
 82             }
 83         }
 84 
 85         [EnvironmentPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)]
 86         private static byte[] GetPixels(Bitmap image, out int rows, out int columns)
 87         {
 88             rows = image.Height;
 89             columns = image.Width;
 90 
 91             if (rows % 2 != 0 && columns % 2 != 0)
 92                 --columns;
 93 
 94             var data = image.LockBits(new Rectangle(0, 0, columns, rows), ImageLockMode.ReadOnly, image.PixelFormat);
 95             var bmpData = data.Scan0;
 96             try
 97             {
 98                 var stride = columns * 3;
 99                 var size = rows * stride;
100                 var pixelData = new byte[size];
101                 for (var i = 0; i < rows; ++i)
102                     Marshal.Copy(new IntPtr(bmpData.ToInt64() + i * data.Stride), pixelData, i * stride, stride);
103 
104                 // Swap BGR to RGB
105                 SwapRedBlue(pixelData);
106                 return pixelData;
107             }
108             finally
109             {
110                 image.UnlockBits(data);
111             }
112         }
113 
114         private static void SwapRedBlue(byte[] pixels)
115         {
116             for (var i = 0; i < pixels.Length; i += 3)
117             {
118                 var temp = pixels[i];
119                 pixels[i] = pixels[i + 2];
120                 pixels[i + 2] = temp;
121             }
122         }
123 
124         private static readonly bool _imageCompression = false;
125 
126     }

调用处代码,Winfrom窗体中包含 selectImageFileButton按钮,一个OpenFileDialog控件,一个PictureBox控件。

 1 private void selectImageFileButton_Click(object sender, EventArgs e)
 2         {
 3             openFileDialog1.Filter = "图片|*.jpg;*.jpeg;*.bmp;*.png";
 4             openFileDialog1.ShowDialog();
 5             openFileDialog1.Multiselect = false;
 6             string imgaeFileName = openFileDialog1.FileName;
 7             if (!string.IsNullOrEmpty(imgaeFileName))
 8             {
 9                 uploadingImagePictureBox.Image = Image.FromFile(imgaeFileName);
10                 Random random = new Random(Guid.NewGuid().GetHashCode());
11                 DicomUploadInfo dicomUploadInfo = new DicomUploadInfo
12                 {
13                     PatientId = Guid.NewGuid().ToString(),
14                     PatientName = "zhangsan",
15                     PatientGender = "M",
16                     PatientDob = DateTime.Now.AddDays(random.Next(-1000, 1000)).ToString("yyyyMMdd"),
17                     StudyTime = DateTime.Now.AddDays(random.Next(-1000, 1000)),
18                     AccessionNumber = "US" + DateTime.Now.ToString("yyyyMMddHHmmss")
19                 };
20                 string strStudyUid = string.Empty;
21                 DicomUID imageUid = GenerateUid();
22                 DicomUID seriesUid = GenerateUid();
23                 DicomUploadImageInfo dicomUploadImageInfo = new DicomUploadImageInfo
24                 {
25                     ImageInfoId = Guid.NewGuid(),
26                     ImageFileName = imgaeFileName,
27                     Modality = "US",
28                     TargetFileName = $"{imgaeFileName}.dcm"
29                 };
30                 ConverttHelper.ImageFileToDicomFile(dicomUploadImageInfo, dicomUploadInfo, GetStudyUid(ref strStudyUid), seriesUid, imageUid);
31             }
32         }
33 
34         private DicomUID GetStudyUid(ref string studyUid)
35         {
36             DicomUID uid;
37             if (string.IsNullOrEmpty(studyUid))
38             {
39                 uid = GenerateUid();
40                 studyUid = uid.UID;
41             }
42             else
43             {
44                 uid = DicomUID.Parse(studyUid);
45             }
46             return uid;
47         }
48 
49         private static readonly object _lockGenerateUidObject = new object();
50         private DicomUID GenerateUid()
51         {
52             lock (_lockGenerateUidObject)
53             {
54                 Random random = new Random(Guid.NewGuid().GetHashCode());
55                 StringBuilder uidBuilder = new StringBuilder();
56                 string uidSeed = GetIPAddress() + ".";
57                 uidBuilder.Append("1.2.826.0.1.3680043.9.5115").Append('.').Append(uidSeed).Append(DateTime.UtcNow.Ticks).Append(random.Next(0, 1000).ToString("D3")); // D3 十进制数,不足3位时前面补0
58                 return new DicomUID(uidBuilder.ToString(), "SOP Instance UID", DicomUidType.SOPInstance);
59             }
60         }
61 
62         public string GetIPAddress()
63         {
64             IPAddress ipAddress = Dns.GetHostAddresses(Dns.GetHostName()).FirstOrDefault(p => p.AddressFamily == AddressFamily.InterNetwork);
65             return ipAddress != null ? ipAddress.ToString() : string.Empty;
66         }