irc-netcore-api/IRC.Core.SCP/Service/DicomArchiveService.cs

357 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using IRaCIS.Core.Domain.Share;
using System.Text;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using FellowOakDicom;
using FellowOakDicom.Imaging.Codec;
using System.Data;
using IRaCIS.Core.Domain.Models;
using FellowOakDicom.Network;
using IRaCIS.Core.SCP.Service;
using IRaCIS.Core.Infra.EFCore;
using MassTransit;
using System.Runtime.Intrinsics.X86;
using Serilog.Sinks.File;
namespace IRaCIS.Core.SCP.Service
{
public class DicomArchiveService : BaseService, IDicomArchiveService
{
private readonly IRepository<SCPPatient> _patientRepository;
private readonly IRepository<SCPStudy> _studyRepository;
private readonly IRepository<SCPSeries> _seriesRepository;
private readonly IRepository<SCPInstance> _instanceRepository;
private readonly IRepository<Dictionary> _dictionaryRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
private List<Guid> _instanceIdList = new List<Guid>();
public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
IRepository<SCPSeries> seriesRepository,
IRepository<SCPInstance> instanceRepository,
IRepository<Dictionary> dictionaryRepository,
IDistributedLockProvider distributedLockProvider)
{
_distributedLockProvider = distributedLockProvider;
_studyRepository = studyRepository;
_patientRepository = patientRepository;
_seriesRepository = seriesRepository;
_instanceRepository = instanceRepository;
_dictionaryRepository = dictionaryRepository;
}
/// <summary>
/// 单个文件接收 归档
/// </summary>
/// <param name="dataset"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize)
{
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
var isStudyNeedAdd = false;
var isSeriesNeedAdd = false;
var isInstanceNeedAdd = false;
var isPatientNeedAdd = false;
//var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
//using (@lock.Acquire())
{
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId );
var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId);
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
//先传输了修改了患者编号的又传输了没有修改患者编号的导致后传输的没有修改患者编号的下面的检查为0
if (findPatient == null && findStudy==null)
{
isPatientNeedAdd = true;
findPatient = new SCPPatient()
{
Id = NewId.NextSequentialGuid(),
TrialId=trialId,
TrialSiteId=trialSiteId,
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
EarliestStudyTime = studyTime,
LatestStudyTime = studyTime,
LatestPushTime = DateTime.Now,
};
if (findPatient.PatientBirthDate.Length == 8)
{
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
int year = 0;
var canParse = int.TryParse(yearStr, out year);
if (canParse && year > 1900)
{
findPatient.PatientBirthDate = birthDateStr;
DateTime birthDate;
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
{
var patientAge = studyTime.Value.Year - birthDate.Year;
// 如果生日还未到,年龄减去一岁
if (studyTime.Value < birthDate.AddYears(patientAge))
{
patientAge--;
}
findPatient.PatientAge = patientAge.ToString();
}
}
else
{
findPatient.PatientBirthDate = string.Empty;
}
}
}
else
{
if (studyTime < findPatient.EarliestStudyTime)
{
findPatient.EarliestStudyTime = studyTime;
}
if (studyTime > findPatient.LatestStudyTime)
{
findPatient.LatestStudyTime = studyTime;
}
findPatient.LatestPushTime = DateTime.Now;
}
if (findStudy == null)
{
isStudyNeedAdd = true;
findStudy = new SCPStudy
{
CalledAE = calledAE,
CallingAE = callingAE,
PatientId = findPatient.Id,
Id = studyId,
TrialId = trialId,
TrialSiteId = trialSiteId,
StudyInstanceUid = studyInstanceUid,
StudyTime = studyTime,
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
//ModalityForEdit = modalityForEdit,
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
//需要特殊处理
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
//IsDoubleReview = addtionalInfo.IsDoubleReview,
SeriesCount = 0,
InstanceCount = 0
};
if (findStudy.PatientBirthDate.Length == 8)
{
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
}
}
if (findSerice == null)
{
isSeriesNeedAdd = true;
findSerice = new SCPSeries
{
Id = seriesId,
StudyId = findStudy.Id,
StudyInstanceUid = findStudy.StudyInstanceUid,
SeriesInstanceUid = seriesInstanceUid,
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
InstanceCount = 0
};
++findStudy.SeriesCount;
}
if (findInstance == null)
{
isInstanceNeedAdd = true;
findInstance = new SCPInstance
{
Id = instanceId,
StudyId = findStudy.Id,
SeriesId = findSerice.Id,
StudyInstanceUid = findStudy.StudyInstanceUid,
SeriesInstanceUid = findSerice.SeriesInstanceUid,
SopInstanceUid = sopInstanceUid,
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
//InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)),
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
CPIStatus = false,
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
Path = fileRelativePath,
FileSize= fileSize,
};
++findStudy.InstanceCount;
++findSerice.InstanceCount;
}
if (isPatientNeedAdd)
{
var ss = await _patientRepository.AddAsync(findPatient);
}
if (isStudyNeedAdd)
{
var dd = await _studyRepository.AddAsync(findStudy);
}
else
{
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.Id, t => new SCPStudy() { IsUploadFinished = false });
}
if (isSeriesNeedAdd)
{
await _seriesRepository.AddAsync(findSerice);
}
if (isInstanceNeedAdd)
{
await _instanceRepository.AddAsync(findInstance);
}
else
{
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize });
}
await _studyRepository.SaveChangesAsync();
return findStudy.Id;
}
}
// 从DICOM文件中获取使用的字符集
private string GetEncodingVaulueFromDicomFile(DicomDataset dataset, DicomTag dicomTag)
{
// 获取DICOM文件的特定元素通常用于指示使用的字符集
var charset = dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
var dicomEncoding = DicomEncoding.GetEncoding(charset);
var dicomStringElement = dataset.GetDicomItem<DicomStringElement>(dicomTag);
var bytes = dicomStringElement.Buffer.Data;
return dicomEncoding.GetString(bytes);
//// 从DICOM文件中获取使用的字符集
//string filePath = "C:\\Users\\hang\\Documents\\WeChat Files\\wxid_r2imdzb7j3q922\\FileStorage\\File\\2024-05\\1.2.840.113619.2.80.169103990.5390.1271401378.4.dcm";
//DicomFile dicomFile = DicomFile.Open(filePath);
//// 获取DICOM文件的特定元素通常用于指示使用的字符集
//var charset = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
//var dicomEncoding = DicomEncoding.GetEncoding(charset);
//var value = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
//var dicomStringElement = dicomFile.Dataset.GetDicomItem<DicomStringElement>(DicomTag.PatientName);
//var bytes = dicomStringElement.Buffer.Data;
//var aa= dicomEncoding.GetString(bytes);
}
}
}