NodeJs访问PACS系统进行DICOM影像的查询和下载等操作

3 篇文章 0 订阅

公司原来使用兄弟公司的C++开发的API访问PACS系统,但因为效率等因素,还是需要有我们自己的一套系统,所以我这里使用第三方DICOM DIMSE services插件dicom-dimse-native开发了自己的一套API来访问PACS。

在此之前,我们需要先有一套测试的PACS系统,我们可以用德国offis公司提供的开源项目DCMTK来搭建一个测试PACS服务器。

如何搭建大家可以百度搜索,这里只进行简单流程介绍。

1、win系统的话,从官网下载对应版本安装包。

2、直接解压缩

3、将解压缩后的\etc\dcmtk\目录下dcmqrscp.cfg文件复制一份到\bin目录下,并修改为以下配置:

NetworkTCPPort  = 108    #PACS服务器的端口号,下载上传需要用到(注意防火墙允许)
MaxPDUSize      = 16384
MaxAssociations = 16

HostTable BEGIN
#客户机的 AETitle,主机名(客户机命令行打hostname即可看到),端口号(注意防火墙允许)
acme1           = (HOSTNAME1, DESKTOP-701Q97F, 5678)
acme2           = (HOSTNAME2, jin, 5678)
acmeCTcompany   = acme1, acme2
HostTable END

VendorTable BEGIN
"Acme CT Company"   = acmeCTcompany #分组
VendorTable END

AETable BEGIN
#服务器AETitle DICOM文件保存地址 读写权限 最大Studies和字节数 分组
WINQR   C:\dcmqrscp   RW (200, 1024mb)   acmeCTcompany
AETable END

4、在\bin目录下启动cmd命令行,执行命令

dcmqrscp.exe -d --config dcmqrscp.cfg

即可启动,如看到以下显示即启动成功

D: $dcmtk: dcmqrscp v3.6.7 2022-04-22 $
D:

5、可以另启动一个cmd窗口(必须到bin目录下),用dcmtk系统自带的工具测试下联通性(假设服务器IP为192.168.1.100)

echoscu.exe -d 192.168.1.100 108 -aec WINQR -aet HOSTNAME1

看到返回的命令行末尾有

I: Received Echo Response (Success)
I: Releasing Association

提示则代表联通成功,如果有错误提示则根据错误提示解决,这里不详细介绍。(最好一台服务器一台客户机,不要在一台上测试)

6、现在PACS测试服中还没有DICOM,我们用命令行工具上传一些DICOM文件,假设DICOM文件都在本机C:\dicom目录下,在本机的命令行输入

storescu.exe -d 192.168.1.100 C:\dicom -aec WINQR -aet HOSTNAME2 +sd

即可上传成功,如果提示错误根据提示处理,一般都是一些权限设置,防火墙等问题。

7、在\man目录下有各种工具命令的详细说明文档,可以自行查看。

好了,经过以上步骤我们的PACS测试服已经搭建好了,现在需要我们写NodeJs代码来访问PACS了。

1、从PACS查询DICOM数据

以下是findScu的方法:

/**
   * findScu PACS查找DICOM
   * @param PatientName 患者姓名
   * @param PatientID 患者ID(病历号)
   * @param StudyDate 检查日期
   * @param instrument 仪器种类
   * @returns 数据列表
   */
  async findScu(
    PatientName: string,
    PatientID: string,
    StudyDate: string,
    instrument: string = 'DX'
  ): Promise<any> {
    const options: findScuOptions = {
      source: {
        //本机的AETitle,IP,端口号
        aet: 'HOSTNAME1',
        ip: '192.168.1.99',
        port: 5678,
      },
      target: {
        //服务器的AETitle,IP,端口号
        aet: 'WINQR',
        ip: '192.168.1.100',
        port: 108,
      },
      tags: [
        {
          key: '00100010', //PatientName 这些是查询条件,不是所有PACS都支持以下所有TAG的查询的,但前三个一般都支持
          value: PatientName,
        },
        {
          key: '00100020', //PatientID
          value: PatientID,
        },
        {
          key: '00080020', //StudyDate
          value: StudyDate,
        },
        {
          key: '00100040', //患者性别
          value: '',
        },
        {
          key: '00200010', //StudyID
          value: '',
        },
        {
          key: '00100030', //患者出生日期
          value: '',
        },
        {
          key: '0020000D', //StudyInstanceUID
          value: '',
        },
        {
          key: '00180015', //检查部位
          value: '',
        },
        {
          key: '00081090', //设备
          value: '',
        },
        {
          key: '00080060', //仪器
          value: instrument,
        },
        {
          key: '00080052',
          value: 'STUDY',
        },
      ],
      verbose: true,
    };
    return new Promise((resolve, reject) => {
      findScu(options, result => {
        let rst = JSON.parse(result);
        console.log('rst=============================', rst); //打印看看结果
        let data = [];
        if (rst['code'] == 0 && rst['container']) {
          data = JSON.parse(rst['container']);
        }
        resolve(data);
      });
    });
  }

2、从PACS下载DICOM

/**
   * moveScu PACS拉取DICOM
   * @param StudyInstanceUID 用唯一的StudyInstanceUID作为下载查询条件
   * @returns 返回下载文件存放目录
   */
  async moveScu(StudyInstanceUID: string): Promise<string> {
    let savePath = 'c:/dicom_save'; //下载的DICOM文件保存地址

    const scpOptions: storeScpOptions = {
      source: {
        //本机的AETitle,IP,端口号
        aet: 'HOSTNAME1',
        ip: '192.168.1.99',
        port: 5678,
      },
      peers: [
        {
          //服务器的AETitle,IP,端口号
          aet: 'WINQR',
          ip: '192.168.1.100',
          port: 108,
        },
      ],
      storagePath: savePath,
      netTransferPrefer: '1.2.840.10008.1.2.4.80', // preferred network transfer syntax (accepted ts - additional to default ts)
      netTransferPropose: '1.2.840.10008.1.2.4.80', // proposed network transfer syntax (for outgoing associations - additional to default ts)
      writeTransfer: '', // write transfer syntax (storage only, recompress on the fly), keep empty to store ts as original
      permissive: false,
      verbose: true,
    };
    //开启传输
    startStoreScp(scpOptions, result => {
      console.log(
        'startStoreScp_result=============================',
        JSON.parse(result)
      );
    });

    const moveOptions: moveScuOptions = {
      source: {
        //本机的AETitle,IP,端口号
        aet: 'HOSTNAME1',
        ip: '192.168.1.99',
        port: 5678,
      },
      target: {
        //服务器的AETitle,IP,端口号
        aet: 'WINQR',
        ip: '192.168.1.100',
        port: 108,
      },
      tags: [
        {
          key: '0020000D',
          value: StudyInstanceUID,
        },
        {
          key: '00080052',
          value: 'STUDY',
        },
      ],
      destination: 'HOSTNAME1', // e.g. sending to ourself
      verbose: true,
    };
    return new Promise((resolve, reject) => {
      //需要一定延时
      setTimeout(() => {
        moveScu(moveOptions, result => {
          let rst = JSON.parse(result);
          if (rst['code'] == '0') {
            let dir = path.join(savePath, StudyInstanceUID);
            if (fs.existsSync(dir)) {
              resolve(dir);
            }
          }
          resolve('');
        });
      }, 3000);
    });
  }

3、其他如​storescp​,storescu等操作,大家可以参考github上的示例

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值