当前位置:   article > 正文

自己做的一个用于生成DICOM文件的服务器

自己做的一个用于生成DICOM文件的服务器

框架: .ner core web api  .net8.0

Program.cs代码如下
  1. using Microsoft.AspNetCore.HttpsPolicy;
  2. using System.Diagnostics;
  3. namespace PacsServer
  4. {
  5. /* public class Program
  6. {
  7. public static void Main(string[] args)
  8. {
  9. //配置服务
  10. var builder = WebApplication.CreateBuilder(args);
  11. // 添加控制器服务,允许控制器处理HTTP请求
  12. builder.Services.AddControllers();
  13. //创建服务器
  14. var app = builder.Build();
  15. // 设置自定义端口,默认为 5000
  16. var port = "5001";
  17. if (args.Length > 0)
  18. {
  19. port = args[0]; // 从命令行参数中获取端口号
  20. }
  21. //监听端口
  22. app.Urls.Add($"http://localhost:{port}");
  23. app.MapControllers();
  24. //允许服务器
  25. app.Run();
  26. }
  27. }*/
  28. public class Program
  29. {
  30. public static void Main(string[] args)
  31. {
  32. // 配置服务
  33. var builder = WebApplication.CreateBuilder(args);
  34. // 添加控制器服务,允许控制器处理 HTTP 请求
  35. builder.Services.AddControllers();
  36. //配置网页启动端
  37. /* builder.Services.AddEndpointsApiExplorer();
  38. builder.Services.AddSwaggerGen();*/
  39. // 创建服务器
  40. var app = builder.Build();
  41. // 设置自定义端口,默认为 5000,暂关闭
  42. /*var port = "45101";
  43. if (args.Length > 0)
  44. {
  45. port = args[0]; // 从命令行参数中获取端口号
  46. }*/
  47. // 监听端口,部署iis上,暂关闭内部端口设置
  48. //app.Urls.Add($"http://localhost:{port}");
  49. //配置网页启动
  50. /* if (app.Environment.IsDevelopment())
  51. { }
  52. app.UseSwagger();
  53. app.UseSwaggerUI();
  54. app.UseHttpsRedirection();
  55. app.UseAuthorization();*/
  56. app.MapControllers();
  57. // 自动打开浏览器访问应用程序
  58. //var url = $"http://localhost:{port}/swagger/index.html";
  59. //var url = $"{Environment.GetEnvironmentVariable("ASPNETCORE_URLS")}/swagger/index.html";
  60. //OpenBrowser(url);
  61. // 允许服务器
  62. app.Run();
  63. }
  64. private static void OpenBrowser(string url)
  65. {
  66. try
  67. {
  68. // 根据平台启动浏览器
  69. Process.Start(new ProcessStartInfo
  70. {
  71. FileName = url,
  72. UseShellExecute = true
  73. });
  74. }
  75. catch (Exception ex)
  76. {
  77. Console.WriteLine($"无法启动浏览器: {ex.Message}");
  78. }
  79. }
  80. }
  81. }
Model.Patient的代码如下
 
  1. using System;
  2. using System.ComponentModel.DataAnnotations;
  3. using System.Reflection;
  4. namespace PacsServer.Model
  5. {
  6. public class Patient
  7. {
  8. public long CheckID { get; set; }
  9. public string PicturePath { get; set; }
  10. public string PatientName { get; set; }
  11. public int PatientAge { get; set; }
  12. public string PatientID { get; set; }
  13. public string CheckDate { get; set; }
  14. public string DicomFilePath { get; set; }
  15. public bool AreRequiredPropertiesValid()
  16. {
  17. foreach (PropertyInfo prop in typeof(Patient).GetProperties())
  18. {
  19. if (prop.Name != nameof(PatientID) && prop.Name != nameof(DicomFilePath))
  20. {
  21. var value = prop.GetValue(this);
  22. if (value == null || (value is string strValue && string.IsNullOrWhiteSpace(strValue)))
  23. {
  24. return false;
  25. }
  26. }
  27. }
  28. return true;
  29. }
  30. }
  31. }
Func.DIcomFunc的代码如下
 
  1. using FellowOakDicom;
  2. using FellowOakDicom.Imaging;
  3. using FellowOakDicom.IO.Buffer;
  4. using FellowOakDicom.Network.Client;
  5. using FellowOakDicom.Network;
  6. using PacsServer.Controllers;
  7. using PacsServer.Model;
  8. using System.Data;
  9. using System.Diagnostics;
  10. using System.Drawing;
  11. using Xunit;
  12. using Newtonsoft.Json;
  13. namespace PacsServer.Func
  14. {
  15. public class DicomFunc
  16. {
  17. public DicomFunc()
  18. {
  19. }
  20. public static void DicomCreat(Patient patientMsg)
  21. {
  22. //判断数据是否存在异常
  23. if (!patientMsg.AreRequiredPropertiesValid())
  24. {
  25. return;
  26. }
  27. //检测图片格式是否正常
  28. string[] validExtensions = { ".jpg", ".jpeg", ".bmp", ".png", ".gif", ".tiff" };
  29. bool isTruePath = validExtensions.Any(ext => patientMsg.PicturePath.EndsWith(ext, StringComparison.OrdinalIgnoreCase));
  30. if (!isTruePath)
  31. {
  32. return;
  33. }
  34. //日期格式纠正
  35. DateTime birthDate = DateTime.ParseExact(patientMsg.CheckDate, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture).Date;
  36. patientMsg.CheckDate = birthDate.ToString("yyyyMMdd");
  37. //年龄纠正
  38. string patientAgeString = patientMsg.PatientAge.ToString("D3") + "Y";
  39. patientMsg.PatientID = patientMsg.PatientName + patientMsg.PatientAge; //暂时定义为名字+年龄
  40. byte[] pixels;
  41. using (Bitmap bitmap = new Bitmap(patientMsg.PicturePath))
  42. {
  43. pixels = GetPixels(bitmap); // 读取像素数据
  44. //using 语句块结束时,Bitmap 资源会被自动释放
  45. MemoryByteBuffer buffer = new MemoryByteBuffer(pixels);
  46. //设置数据集
  47. var dataset = new DicomDataset
  48. {
  49. { DicomTag.SpecificCharacterSet,"GB18030" },
  50. { DicomTag.PatientName, patientMsg.PatientName },
  51. { DicomTag.PatientID, patientMsg.PatientID },
  52. { DicomTag.PatientAge, patientAgeString},
  53. { DicomTag.StudyDate, patientMsg.CheckDate},
  54. { DicomTag.SeriesDate, patientMsg.CheckDate },
  55. { DicomTag.PhotometricInterpretation, PhotometricInterpretation.Rgb.Value },
  56. { DicomTag.Rows, (ushort)bitmap.Height },
  57. { DicomTag.Columns, (ushort)bitmap.Width },
  58. { DicomTag.BitsAllocated, (ushort)8 },
  59. { DicomTag.BitsStored, (ushort)8 },
  60. { DicomTag.HighBit, (ushort)7 },
  61. { DicomTag.SamplesPerPixel, (ushort)3 },
  62. { DicomTag.SOPClassUID, DicomUID.VideoEndoscopicImageStorage }, //内窥镜成像
  63. { DicomTag.SOPInstanceUID, DicomUID.Generate() }
  64. };
  65. //同次检查判断
  66. PatientService _patientService = new PatientService();
  67. var uidClass = _patientService.GetOrCreateUIDs(patientMsg.CheckID);
  68. dataset.AddOrUpdate(DicomTag.StudyInstanceUID, uidClass.GetStudyInstanceUID());
  69. dataset.AddOrUpdate(DicomTag.SeriesInstanceUID, uidClass.GetSeriesInstanceUID());
  70. //设置像素数据
  71. DicomPixelData pixelData = DicomPixelData.Create(dataset, true);
  72. pixelData.BitsStored = 8;
  73. pixelData.SamplesPerPixel = 3;
  74. pixelData.HighBit = 7;
  75. pixelData.PixelRepresentation = PixelRepresentation.Unsigned;
  76. pixelData.PlanarConfiguration = PlanarConfiguration.Interleaved;
  77. pixelData.AddFrame(buffer);
  78. DicomFile dicomFile = new DicomFile(dataset);
  79. int index = patientMsg.PicturePath.LastIndexOf('\\');
  80. string filePath = patientMsg.PicturePath.Substring(0, index) + "\\dcmfile";
  81. string imagePath = patientMsg.PicturePath.Substring(index + 1);
  82. imagePath = System.IO.Path.GetFileNameWithoutExtension(imagePath);
  83. if (!Directory.Exists(filePath))
  84. {
  85. Directory.CreateDirectory(filePath);
  86. }
  87. patientMsg.DicomFilePath = filePath + "\\" + imagePath + ".dcm";
  88. dicomFile.Save(patientMsg.DicomFilePath);
  89. Console.WriteLine("createSuccess");
  90. //能否ping通
  91. if (PacsConfigController.IsServerReachable)
  92. {
  93. DicomUpdataAsync(patientMsg.DicomFilePath);
  94. Console.WriteLine("uploadSuccess");
  95. }
  96. else
  97. {
  98. Console.WriteLine("pacs服务器不可达!");
  99. }
  100. }
  101. }
  102. /// <summary>
  103. /// 上传dcm文件
  104. /// </summary>
  105. /// <param name="dicomFilePath"></param>
  106. /// <exception cref="InvalidOperationException"></exception>
  107. /// <exception cref="TimeoutException"></exception>
  108. private static async void DicomUpdataAsync(string dicomFilePath)
  109. {
  110. var client = DicomClientFactory.Create(ServerConfig.ServerAddress, int.Parse(ServerConfig.Port), false, "Colposcope", ServerConfig.AET);
  111. client.ClientOptions.AssociationRequestTimeoutInMs = (int)TimeSpan.FromMinutes(5).TotalMilliseconds;
  112. DicomCStoreResponse response = null;
  113. DicomRequest.OnTimeoutEventArgs timeout = null;
  114. try
  115. {
  116. var request = new DicomCStoreRequest(dicomFilePath)
  117. {
  118. OnResponseReceived = (req, res) => response = res,
  119. OnTimeout = (sender, args) => timeout = args
  120. };
  121. await client.AddRequestAsync(request);
  122. await client.SendAsync();
  123. // 验证响应
  124. if (response == null) { throw new InvalidOperationException("Response is null."); }
  125. if (response.Status != DicomStatus.Success) { throw new InvalidOperationException("Response status is not successful."); }
  126. if (timeout != null) { throw new TimeoutException("Operation timed out."); }
  127. }
  128. catch (Exception ex)
  129. {
  130. throw;
  131. }
  132. }
  133. public async static Task<bool> DicomPing(ServerConfigDTO server)
  134. {
  135. var client = DicomClientFactory.Create(server.ServerAddress, int.Parse(server.Port), false, "Colposcope", server.AET);
  136. client.ClientOptions.AssociationRequestTimeoutInMs = (int)TimeSpan.FromMinutes(5).TotalMilliseconds; // 设置关联请求超时时间
  137. DicomCEchoResponse response = null;
  138. DicomRequest.OnTimeoutEventArgs timeout = null;
  139. var request = new DicomCEchoRequest
  140. {
  141. OnResponseReceived = (req, res) => response = res, // 响应接收事件
  142. OnTimeout = (sender, args) => timeout = args // 超时事件
  143. };
  144. await client.AddRequestAsync(request); // 添加C-Echo请求
  145. try
  146. {
  147. await client.SendAsync(); // 发送请求
  148. // 验证响应
  149. if (response == null) { return false; }
  150. if (response.Status != DicomStatus.Success){ return false;}
  151. if (timeout != null){ return false;}
  152. return true;
  153. }
  154. catch (Exception ex)
  155. {
  156. return false;
  157. }
  158. }
  159. public static byte[] GetPixels(Bitmap bitmap)
  160. {
  161. byte[] bytes = new byte[bitmap.Width * bitmap.Height * 3];
  162. int width = bitmap.Width;
  163. int height = bitmap.Height;
  164. int i = 0;
  165. for (int y = 0; y < height; y++) //上到下
  166. {
  167. for (int x = 0; x < width; x++) //左到右
  168. {
  169. var srcColor = bitmap.GetPixel(x, y);
  170. //bytes[i] = (byte)(srcColor.R * .299 + srcColor.G * .587 + srcColor.B * .114); // 取消注释生成灰度图
  171. bytes[i] = srcColor.R;
  172. i++;
  173. bytes[i] = srcColor.G;
  174. i++;
  175. bytes[i] = srcColor.B;
  176. i++;
  177. }
  178. }
  179. return bytes;
  180. }
  181. }
  182. public class UIDClass
  183. {
  184. public string StudyInstanceUID { get; private set; }
  185. public string SeriesInstanceUID { get; private set; }
  186. public UIDClass(string studyInstanceUID, string seriesInstanceUID)
  187. {
  188. StudyInstanceUID = studyInstanceUID;
  189. SeriesInstanceUID = seriesInstanceUID;
  190. }
  191. public string GetStudyInstanceUID()
  192. {
  193. return StudyInstanceUID;
  194. }
  195. public string GetSeriesInstanceUID()
  196. {
  197. return SeriesInstanceUID;
  198. }
  199. }
  200. public class PatientService
  201. {
  202. private readonly string filePath;
  203. public PatientService()
  204. {
  205. filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Patient.json");
  206. }
  207. // 加载表中的数据
  208. public Dictionary<long, UIDClass> LoadPatients()
  209. {
  210. if (!File.Exists(filePath))
  211. {
  212. return new Dictionary<long, UIDClass>();
  213. }
  214. var json = File.ReadAllText(filePath);
  215. return JsonConvert.DeserializeObject<Dictionary<long, UIDClass>>(json);
  216. }
  217. // 保存数据到表
  218. public void SavePatients(Dictionary<long, UIDClass> patients)
  219. {
  220. var json = JsonConvert.SerializeObject(patients, Formatting.Indented);
  221. File.WriteAllText(filePath, json);
  222. }
  223. // 获取或创建UIDClass对象
  224. public UIDClass GetOrCreateUIDs(long patientID)
  225. {
  226. var patients = LoadPatients();
  227. if (!patients.TryGetValue(patientID, out var uidClass))
  228. {
  229. uidClass = new UIDClass(
  230. DicomUID.Generate().UID,
  231. DicomUID.Generate().UID
  232. );
  233. patients[patientID] = uidClass;
  234. SavePatients(patients);
  235. }
  236. return uidClass;
  237. }
  238. }
  239. }
Controllers.DicomController的代码如下
 
  1. using Microsoft.AspNetCore.Mvc;
  2. using PacsServer.Func;
  3. using PacsServer.Model;
  4. namespace PacsServer.Controllers
  5. {
  6. [Route("api/[controller]")]
  7. [ApiController]
  8. public class DicomController : ControllerBase
  9. {
  10. [HttpPost("execute")]
  11. public IActionResult Execute([FromBody] Patient patientMsg)
  12. {
  13. if (patientMsg == null || !ModelState.IsValid)
  14. {
  15. foreach (var error in ModelState.Values.SelectMany(v => v.Errors))
  16. {
  17. Console.WriteLine(error.ErrorMessage);
  18. }
  19. return BadRequest(ModelState);
  20. }
  21. DicomFunc.DicomCreat(patientMsg);
  22. return Ok("Request processed successfully");
  23. }
  24. }
  25. }
Controllers.PacsConfigController1的代码如下
  1. using Microsoft.AspNetCore.Mvc;
  2. using PacsServer.Func;
  3. namespace PacsServer.Controllers
  4. {
  5. [Route("api/[controller]")]
  6. [ApiController]
  7. public class PacsConfigController : ControllerBase
  8. {
  9. public static bool IsServerReachable { get; set; } = false; //pacs服务器是否可达
  10. [HttpPut("config")]
  11. public async Task<IActionResult> Config([FromBody] ServerConfigDTO serverConfig)
  12. {
  13. if (!ModelState.IsValid)
  14. {
  15. return BadRequest(ModelState);
  16. }
  17. //赋值逻辑
  18. ServerConfig.ServerAddress = serverConfig.ServerAddress;
  19. ServerConfig.Port = serverConfig.Port;
  20. ServerConfig.AET = serverConfig.AET;
  21. IsServerReachable = await DicomFunc.DicomPing(serverConfig); //测试服务器能否ping通
  22. if (IsServerReachable)
  23. {
  24. Console.WriteLine("pingSuccess");
  25. return Ok();
  26. }
  27. else
  28. {
  29. return StatusCode(StatusCodes.Status500InternalServerError, "Failed to ping DICOM server");
  30. }
  31. }
  32. }
  33. public class ServerConfig
  34. {
  35. public static string ServerAddress { get; set; }
  36. public static string Port { get; set; }
  37. public static string AET { get; set; }
  38. }
  39. public class ServerConfigDTO
  40. {
  41. public string ServerAddress { get; set; } = string.Empty;
  42. public string Port { get; set; } = string.Empty;
  43. public string AET { get; set; } = string.Empty;
  44. }
  45. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/1020835?site
推荐阅读
相关标签
  

闽ICP备14008679号