- 示例工程
- 教程
- 后端
【免费下载链接】aws-doc-sdk-examples
Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.
导读
本文围绕 pixel-data-verification 示例,系统讲解如何借助 AWS HealthImaging(AHI,即 AHLI,AWS Health Imaging)的 Pixel Data Verification 能力,通过 JavaScript/Node.js 确认从 AHI 解码出的图像帧与原始 DICOM P10 文件内容完全一致。读完本文,你将掌握「拉取 ImageSet 元数据 → 获取图像帧 → HTJ2K 解码 → 与元数据中声明的 CRC32 校验和比对」的完整链路,并理解其在医疗影像数据完整性验证中的实战用法。
背景:为什么要做像素数据校验
DICOM(Digital Imaging and Communications in Medicine)是医学影像数字化存储与传输的国际标准。AWS HealthImaging 在导入 DICOM 文件后,会将原始 P10 文件转换为 HTJ2K 编码的中间格式(image frame)供高效检索与分发。由于图像帧在存储、传输与解码过程中可能发生损坏或篡改,AHI 在生成每个图像帧时计算了从原始像素数据到完整分辨率(base-to-full-resolution)的 CRC32 校验和序列,并随 ImageSet 元数据一起返回。客户端解码后自行重新计算 CRC32 并与元数据声明值比对,即可端到端确认「解码结果 == 原始 DICOM 像素数据」。
本示例即该验证流程的最小可运行实现,代码位于 index.js,配套的集成调用场景见 health-image-sets 工作流。
依赖与环境
该示例使用 JavaScript 与 Node.js 编写,核心依赖如下(见 package.json):
| 依赖 | 版本/形态 | 作用 |
|---|---|---|
AWS SDK for JavaScript v3(@aws-sdk/client-medical-imaging) | ^3.427.0 | 调用GetImageSetMetadataCommand与GetImageFrameCommand两个 AHI API |
crc-32 | ^1.2.2 | 计算解码后像素缓冲区的 CRC32 校验和 |
openjphjs(HTJ2K 解码) | 仓库内置 WASM 构建(openjphjs/openjphjs.js +openjphjs.wasm) | 将 AHI 返回的 HTJ2K 编码图像帧解码为原始像素位图 |
其中openjphjs是 openjph(HTJ2K 编解码库)的 JavaScript/WebAssembly 构建,以本地模块形式随示例分发,对应的第三方许可声明见 THIRD-PARTY-LICENSES。
此外package.json的 devDependencies 中还包含vitest ^1.6.0,用于对上层场景做单元测试(详见下文「测试」一节)。
部署:三步安装
按照原文档步骤执行即可:
# 1. 检出项目(克隆仓库) # 2. 切换到示例目录 cd javascriptv3/example_code/medical-imaging/scenarios/health-image-sets/pixel-data-verification # 3. 安装依赖 npm installnpm install会安装@aws-sdk/client-medical-imaging与crc-32两个 npm 依赖;openjphjs无需额外安装,直接通过require("./openjphjs/openjphjs.js")从本地加载。
使用方法:完整操作步骤
前提准备
- 创建 Datastore:按照 AWS HealthImaging(AHLI)开发者指南创建数据存储(datastore),并获得
DATASTOREID; - 导入 DICOM 文件:按照开发者指南,将示例 DICOM 文件 test/fixtures/CT1_UNC 作为 DICOM 导入作业的输入导入到上述 datastore;
- 获取 ImageSetId:DICOM 导入作业完成后,从 S3 中的作业输出清单(manifest)文件里读取由该导入产生的
IMAGESETID; - 准备 UID:记录待验证的 series 与 SOP instance UID。
运行命令
按顺序传入DATASTOREID、IMAGESETID、series 与 SOP instance UID:
$ node index.js $DATASTOREID $IMAGESETID 1.3.6.1.4.1.5962.1.3.1.1.20040826185059.5457 1.3.6.1.4.1.5962.1.1.1.1.1.20040826185059.5457 CRC32 match!示例中使用的 UID 与仓库内置测试数据CT1_UNC对应:1.3.6.1.4.1.5962.1.3.1.1.20040826185059.5457为 series instance UID,1.3.6.1.4.1.5962.1.1.1.1.1.20040826185059.5457为 SOP instance UID。若校验通过,控制台输出CRC32 match!;若不一致,则输出CRC32 does NOT match!。
源码级原理剖析
整体数据流
index.js 的执行流程可分为五步:
- 获取并解压 ImageSet 元数据:调用
GetImageSetMetadataCommand得到 gzip 压缩的元数据 Blob,用node:zlib的gunzip解压后JSON.parse; - 按 UID 查找图像帧 ID:在元数据树
Study.Series[seriesInstanceUid].Instances[sopInstanceUid].ImageFrames中取第一个图像帧的ID; - 获取图像帧:调用
GetImageFrameCommand,以{ datastoreId, imageSetId, imageFrameInformation: { imageFrameId } }为参数拉取 HTJ2K 编码的imageFrameBlob; - HTJ2K 解码:把字节填入
openjphjs的HTJ2KDecoder编码缓冲区并调用decode(),得到解码后的原始像素缓冲区; - CRC32 比对:用
crc-32计算解码缓冲区的校验和,与元数据中声明的完整分辨率校验和比较,输出结论。
元数据的获取与解析
const getImageSetMetadataInput = { datastoreId: datastoreId, imageSetId: imageSetId, }; const getImageSetMetadataCmd = new GetImageSetMetadataCommand(getImageSetMetadataInput); const getImageSetMetadataRsp = await miClient.send(getImageSetMetadataCmd); const imageSetMetadataBlobByteArray = await getImageSetMetadataRsp.imageSetMetadataBlob.transformToByteArray(); const imageSetMetadataBuffer = await gunzip(imageSetMetadataBlobByteArray); const imageSetMetadata = JSON.parse(imageSetMetadataBuffer);关键点在于响应的imageSetMetadataBlob是contentEncoding: gzip、contentType: application/json的流式 Blob(参见 actions/get-image-set-metadata.js 中同样的调用形态),必须先transformToByteArray()再gunzip才能得到可解析的 JSON 文本。解压后的元数据顶层结构包含SchemaVersion、DatastoreID、ImageSetID、Patient、Study等字段,其中Study.Series以 series instance UID 为键,其下Instances以 SOP instance UID 为键(该结构的 TypeScript 风格定义可参见 verify-steps.js 顶部的 JSDoc@typedef)。
按 UID 定位图像帧与校验和声明
const getImageFrameForSopInstance = (metadata, seriesInstanceUid, sopInstanceUid) => { try { return metadata.Study.Series[seriesInstanceUid].Instances[sopInstanceUid].ImageFrames; } catch (e) { throw "Unable to get image frame ID from metadata. Check series and SOP instance UIDs."; } };每个图像帧对象含ID(图像帧唯一标识)与PixelDataChecksumFromBaseToFullResolution(从基础分辨率到完整分辨率的逐级校验和数组,元素含Checksum、Height、Width)等字段。示例取数组最后一个元素作为完整分辨率(full resolution)的最终校验和:
const fullResCRC32FromMeta = imageFrameMeta[0].PixelDataChecksumFromBaseToFullResolution[ imageFrameMeta[0].PixelDataChecksumFromBaseToFullResolution.length - 1 ].Checksum;HTJ2K 解码与 CRC32 计算
openjphjs的 WASM 运行时在onRuntimeInitialized回调就绪后才创建解码器实例,整个过程因此被包裹在该回调内:
openjphjs.onRuntimeInitialized = async (_) => { const decoder = new openjphjs.HTJ2KDecoder(); // ... const encodedBuffer = decoder.getEncodedBuffer(imageFrameData.length); encodedBuffer.set(imageFrameData); decoder.decode(); const decodedBuffer = decoder.getDecodedBuffer(); // ... const fullResCRC32Signed = CRC32.buf(decodedBuffer); const fullResCRC32 = fullResCRC32Signed >>> 0; // convert to unsigned if (fullResCRC32 === fullResCRC32FromMeta) { console.log("CRC32 match!"); } else { console.log("CRC32 does NOT match!"); } };注意CRC32.buf()返回的是有符号32 位整数,而元数据中的Checksum为无符号十进制值,因此必须通过>>> 0位运算转为无符号数后再比较,这是校验能正确命中的关键细节。
客户端初始化与区域配置
const AHI_REGION = ""; const { MedicalImagingClient, GetImageSetMetadataCommand, GetImageFrameCommand } = require("@aws-sdk/client-medical-imaging"); let imagingClientConfig; if (AHI_REGION) imagingClientConfig.endpoint = AHI_REGION; const miClient = new MedicalImagingClient(imagingClientConfig);从源码看,AHI_REGION默认被初始化为空字符串,因此imagingClientConfig保持undefined,客户端将完全采用 AWS SDK 的标准配置链(共享凭证文件、环境变量、IAM 角色等)确定区域与凭证。若需显式指定区域/终端节点,可自行设置AHI_REGION(注意同时需构造imagingClientConfig对象),这为本地模拟服务或非默认分区调试留出了扩展点。
命令行参数约定
if (process.argv.length < 5) { console.log("node index.js <datastoreid> <imagesetid> <seriesInstanceUid> <sopInstanceUid>"); process.exit(1); } const datastoreId = process.argv[2]; const imageSetId = process.argv[3]; const seriesInstanceUid = process.argv[4]; const sopInstanceUid = process.argv[5];位置参数即 README 使用示例中的四个值;参数不足时打印用法并退出。
在端到端场景中的集成方式
pixel-data-verification并非孤立工具,它被 health-image-sets 完整工作流作为「下载 → 解码 → 校验」环节引用。该工作流以node index.js --scenario <deploy | demo | destroy>驱动,通过 CloudFormation 创建 datastore、输入/输出 S3 桶与 IAM 角色,从公共桶拷贝 DICOM 研究、运行导入作业后,调用本验证工具对每个图像帧做校验。
在 verify-steps.js 中,decodeAndVerifyImages以spawn("node", ["./pixel-data-verification/index.js", datastoreId, imageSetId, seriesInstanceUid, sopInstanceUid], { stdio: "inherit" })的方式逐 SOP 实例启动本工具,并监听子进程退出码——退出码为 0 视为校验通过,否则抛出Verification tool exited with code ...错误。也就是说,该工具同时可作为独立的 CLI 命令使用,也可作为更大自动化场景中被编排的校验子进程。
测试验证
仓库为上层场景提供了针对性的单元测试:tests/hlth-img-verify.unit.test.js。测试通过 mocknode:child_process的spawn,构造含两个 image set(一个含 1 个实例、一个含 2 个实例)的元数据状态,断言:
spawn被调用3次(对应 3 个 SOP 实例);- 每次调用均以
"./pixel-data-verification/index.js"为工具路径,并依次传入datastore-123、对应image-set-*、series 与 SOP UID; - 使用
{ stdio: "inherit" }继承标准输入输出。
该测试证明了验证工具与上层场景之间的参数契约(路径、四个位置参数、stdio 行为)是被测试固化的,也是集成其他场景时可参考的调用规范。
常见问题与注意事项
- 报错
Unable to get image frame ID from metadata. Check series and SOP instance UIDs.:说明传入的 series/SOP UID 与 ImageSet 元数据不匹配,请回查导入作业 manifest 与元数据内容; - 输出
CRC32 does NOT match!:解码结果与原始像素不一致,可能源于图像帧在传输中损坏、解码参数错误或校验和取值位置错误(应取PixelDataChecksumFromBaseToFullResolution的最后一个元素); - 忘记
>>> 0转换:直接比较有符号 CRC32 与无符号Checksum在最高位为 1 时会误判失败; - 运行会产生 AWS 费用:涉及 datastore、导入作业与图像帧读取,建议遵循最小权限原则,并注意 AHI 并非在所有区域可用(可参考 health-image-sets README 中的注意事项)。
总结
pixel-data-verification展示了 AHI 像素数据验证特性的标准实现范式:以元数据中的PixelDataChecksumFromBaseToFullResolution为可信基准,用 HTJ2K 解码还原像素后再以 CRC32 复算比对。它既是可独立运行的 CLI 工具,也是 health-image-sets 端到端场景中数据完整性保障的关键一环,为医学影像应用的数据可信校验提供了开箱即用的参考实现。
- 示例工程
- 教程
- 后端
【免费下载链接】aws-doc-sdk-examples
Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.
相关推荐
使用 AWS SDK for C++ 导入 HealthImaging 影像集并下载校验图像帧:imaging_set_and_frames_workflow 实战指南
使用 AWS SDK for C++ 导入 HealthImaging 影像集并下载校验图像帧:imaging_set_and_frames_workflow
示例工程教程后端GPX Studio:如何在浏览器中免费编辑GPS轨迹文件?
GPX Studio:如何在浏览器中免费编辑GPS轨迹文件? 你是否曾经遇到过这样的困扰:手机或运动手表记录的GPS轨迹数据需要编辑整理,却发现专业软件要么价格
示例工程教程后端AWS SDK for Java v2校验和验证:数据传输完整性保障
AWS SDK for Java v2校验和验证:数据传输完整性保障 在分布式系统和大规模数据传输场景中,数据完整性(Data Integrity)是至关重要的
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考