1.前置知识
虽然今天国内医学影像行业较前几年已经发达很多,但是前端方面,关于cornerstone的资料还是比较少。再加上cornerstone本身文档不是特别完善,所以新人上手比较困难。下面讲简单记录一些我关于这个库的探索及理解。下面的表格主要列一下cornerstone主要仓库的作用
仓库名称 | 主要作用 |
---|---|
cornerstoneWADOImageLoader | 加载dicom图,供后期cornerstone展示 |
dicomParser | 解析dicom tag |
cornerstone | 主要用于图像展示 |
cornerstoneTools | cornerstone常用工具封装 |
2.如何画出dicom
下述代码使用react框架,全部使用cornerstone最新版本,主要展示了dicom加载,显示,工具使用及tag解析。仅贴出主要部分,完整代码请参考文章末尾github链接。(由于快速实现需要,请忽略TS部分)
a.初始化cornerstone Externals及cornerstoneWADOImageLoader方法
// cornerstoneWADOImageLoader config配置
const config = {
maxWebWorkers: navigator.hardwareConcurrency || 1,
startWebWorkersOnDemand: true,
taskConfiguration: {
decodeTask: {
initializeCodecsOnStartup: false,
usePDFJS: false,
strict: false,
},
},
};
// 初始化cornerstone Externals及cornerstoneWADOImageLoader方法
function _initCornerstone() {
// Externals
cornerstoneWADOImageLoader.external.cornerstone = cornerstone;
cornerstoneWADOImageLoader.external.dicomParser = dicomParser;
cornerstoneTools.external.cornerstoneMath = cornerstoneMath;
cornerstoneTools.external.cornerstone = cornerstone;
cornerstoneTools.external.Hammer = Hammer;
// Image Loader
cornerstoneWADOImageLoader.webWorkerManager.initialize(config);
}
b.解析tag方法
const parserDicom = (file: any) => {
const reader = new FileReader();
reader.onload = function (file) {
var arrayBuffer = reader.result;
if (!arrayBuffer || typeof arrayBuffer === "string") return;
const byteArray = new Uint8Array(arrayBuffer);
let dataSet;
dataSet = dicomParser.parseDicom(byteArray);
// access a string element
const studyInstanceUid = dataSet.string("x0020000d");
// get the pixel data element (contains the offset and length of the data)
const pixelDataElement = dataSet.elements.x7fe00010;
console.log("dicomParser", studyInstanceUid, pixelDataElement);
};
reader.readAsArrayBuffer(file);
};
c.主函数
function App() {
useEffect(() => {
// 初始化cornerstone相关配置
_initCornerstone();
}, []);
// 处理上传文件
const handleFileSelect = async (e: ChangeEvent<HTMLInputElement>) => {
// 获取展示宿主元素
const element = document.getElementById("dicomImage");
// 初始化工具,此方法必须放在cornerstone.enable(element)前,否则工具可能会无法使用
cornerstoneTools.init({
showSVGCursors: true,
});
// 激活element
cornerstone.enable(element);
// 获取上传文件
const files = e.target.files || [];
const file = files[0];
// 解析相关标签示例
parserDicom(file);
// cornerstoneWADOImageLoader解析文件,获取imageId
const imageId = cornerstoneWADOImageLoader.wadouri.fileManager.add(file);
// 展示dicom
cornerstone.loadImage(imageId).then(function (image: any) {
cornerstone.displayImage(element, image);
});
// 长度工具使用示例
const toolName = "Length";
const apiTool = cornerstoneTools[`${toolName}Tool`];
cornerstoneTools.addTool(apiTool);
// toolName不能使用cornerstoneTools.LengthTool.name, 他们不一样
cornerstoneTools.setToolActive(toolName, { mouseButtonMask: 1 });
};
return (
<div className="App">
<div
className="viewport"
id={"dicomImage"}
style={{ width: "512px", height: "512px", background: "gray" }}
></div>
<input type={"file"} onChange={handleFileSelect}></input>
</div>
);
}
export default App;
附:
链接:github 对于commit:1aa626d
在线预览链接
欢迎同行业朋友交流