文章目录
- 一、MWL简介
- 二、MWL 功能
- 三、MWL 的工作原理
- 1. 信息来源
- 2. 信息传输
- 3. 信息显示和操作
- 四、基于Fo-Dicom实现MWL服务
- 服务端
- 客户端
一、MWL简介
放射科的成像设备工作列表(Modality Work List,MWL) 是一个包含患者检查信息的列表,这些信息通常来自 HIS 或 RIS。它被发送到放射科的成像设备,如 X 光机、CT 扫描仪、MRI 设备等,以指导设备操作人员进行检查。
二、MWL 功能
患者信息管理: MWL 包含患者的基本信息,如姓名、年龄、性别、病历号等。这些信息有助于设备操作人员准确识别患者,避免检查错误。
检查任务分配: MWL 根据患者的检查需求和设备的可用性,将检查任务分配给合适的成像设备。这可以提高设备的利用率,减少患者等待时间。
检查参数设置: MWL 可以提供检查的详细参数,如检查部位、检查方法、成像序列等。这些参数可以帮助设备操作人员快速设置设备,确保检查的准确性和一致性。
检查状态跟踪: MWL 可以实时跟踪检查的状态,如待检查、正在检查、已完成等。这有助于管理人员了解检查进度,及时调整工作计划。
报告生成: MWL 可以与报告系统集成,自动生成检查报告。这可以提高报告的准确性和及时性,减少医生的工作量。
三、MWL 的工作原理
1. 信息来源
MWL 的信息主要来自 HIS 和 RIS。当患者在医院挂号、就诊或预约检查时,相关信息会被录入 HIS 或 RIS。这些信息包括患者的基本信息、临床诊断、检查申请等。
2. 信息传输
MWL 信息通常通过网络传输到放射科的成像设备。这可以通过多种方式实现,如 DICOM(Digital Imaging and Communications in Medicine)协议、HL7(Health Level Seven)协议等。DICOM 协议是医学影像领域的标准通信协议,它可以确保不同厂家的成像设备和信息系统之间的互操作性。
3. 信息显示和操作
成像设备接收到 MWL 信息后,会将其显示在设备的操作界面上。设备操作人员可以查看患者的检查信息,选择需要进行的检查任务,并根据检查参数设置设备。在检查完成后,设备操作人员可以将检查结果上传到 RIS 或 HIS,更新 MWL 的检查状态。
四、基于Fo-Dicom实现MWL服务
服务端
服务端主要实现CFind:完整代码
public class WorklistService : DicomService, IDicomServiceProvider, IDicomCEchoProvider, IDicomCFindProvider
{private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]{DicomTransferSyntax.ExplicitVRLittleEndian,DicomTransferSyntax.ExplicitVRBigEndian,DicomTransferSyntax.ImplicitVRLittleEndian};public string CallingAE { get; protected set; }public string CalledAE { get; protected set; }public WorklistService(INetworkStream stream, Encoding fallbackEncoding, ILogger logger, DicomServiceDependencies dependencies) : base(stream, fallbackEncoding, logger, dependencies){Logger = logger; }public async Task<DicomCEchoResponse> OnCEchoRequestAsync(DicomCEchoRequest request){Logger.LogInformation($"Received verification request from AE { Association.CallingAE } with IP: { Association.RemoteHost }");return await Task.FromResult(new DicomCEchoResponse(request,DicomStatus.Success));}/// <summary>/// 查询/// </summary>/// <param name="request"></param>/// <returns></returns>public async IAsyncEnumerable<DicomCFindResponse> OnCFindRequestAsync(DicomCFindRequest request){if(request.Level != DicomQueryRetrieveLevel.NotApplicable){yield return new DicomCFindResponse(request,DicomStatus.QueryRetrieveUnableToProcess);}else{//根据条件筛选出结果,WorklistServer.CurrentWorklistItems是一个静态结果数据集,可自定义foreach(DicomDataset result in WorklistHandler.FilterWorklistItems(request.Dataset,WorklistServer.CurrentWorklistItems) ){yield return new DicomCFindResponse(request, DicomStatus.Pending) { Dataset = result};}yield return new DicomCFindResponse(request, DicomStatus.Success);}}public void OnConnectionClosed(Exception exception){}public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason){throw new NotImplementedException();}public Task OnReceiveAssociationReleaseRequestAsync(){return SendAssociationReleaseResponseAsync();}public Task OnReceiveAssociationRequestAsync(DicomAssociation association){CallingAE = association.CallingAE;CalledAE = association.CalledAE;Logger.LogInformation($"Received association request from AE: {association.CallingAE} with IP: {association.RemoteHost} ");if (WorklistServer.CalledAE != association.CalledAE){Logger.LogError($"Association with {association.CallingAE} rejected since called aet {association.CalledAE} is unknown");return SendAssociationRejectAsync(DicomRejectResult.Permanent, DicomRejectSource.ServiceUser, DicomRejectReason.CalledAENotRecognized);}foreach (var pc in association.PresentationContexts){if (pc.AbstractSyntax == DicomUID.Verification|| pc.AbstractSyntax == DicomUID.ModalityWorklistInformationModelFind|| pc.AbstractSyntax == DicomUID.ModalityPerformedProcedureStep|| pc.AbstractSyntax == DicomUID.ModalityPerformedProcedureStepNotification|| pc.AbstractSyntax == DicomUID.ModalityPerformedProcedureStepNotification){pc.AcceptTransferSyntaxes(_acceptedTransferSyntaxes);}else{Logger.LogWarning($"Requested abstract syntax {pc.AbstractSyntax} from {association.CallingAE} not supported");pc.SetResult(DicomPresentationContextResult.RejectAbstractSyntaxNotSupported);}}Logger.LogInformation($"Accepted association request from {association.CallingAE}");return SendAssociationAcceptAsync(association);}
客户端
客户端简单发一个CFind请求:
var worklistItems = new List<DicomDataset>();var cfind = DicomCFindRequest.CreateWorklistQuery();cfind.OnResponseReceived = (DicomCFindRequest rq, DicomCFindResponse rp) =>{if(rp.HasDataset){worklistItems.Add(rp.Dataset);}};var client = DicomClientFactory.Create(_mwlIp, _mwlPort,false,_mwlCallingAE,_mwlCalledAE);await client.AddRequestAsync(cfind);await client.SendAsync();return worklistItems;
五、MPPS和MWL服务结合
关于MPPS的介绍,参考前文:MPPS详细介绍
很多时候MPPS服务和MWL服务可以一起实现,不需要分开。
流程:
- 1、设备端通过MWL服务从Worklist查询相关检查信息
- 2、设备将状态更改后,生成一个MPPS实例并通过MPPS服务返回给Worklist
- 3、Worklist根据返回的检查状态进行其他操作
简单的可视化Demo程序