larvitar 0.18.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/deploy.yml +3 -12
- package/MIGRATION.md +25 -0
- package/README.md +28 -27
- package/docs/documentation/Mixins.polygonSegmentationMixin%20-%20segmentation%20operations%20for%20polyline.html +171 -0
- package/docs/documentation/Tools.Annotation.ContoursTool.html +218 -0
- package/docs/documentation/Tools.Annotation.DiameterTool.html +219 -0
- package/docs/documentation/Tools.Annotation.SeedsTool.html +214 -0
- package/docs/documentation/Tools.Brush.BrushTool.html +218 -0
- package/docs/documentation/Tools.Brush.ThresholdsBrushTool.html +218 -0
- package/docs/documentation/Tools.PolylineScissorsTool.html +218 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Bold.eot +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Bold.woff +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Regular.eot +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Regular.woff +0 -0
- package/docs/documentation/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
- package/docs/documentation/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
- package/docs/documentation/global.html +1303 -0
- package/docs/documentation/imageAnonymization.js.html +245 -0
- package/docs/documentation/imageColormaps.js.html +283 -0
- package/docs/documentation/imageContours.js.html +278 -0
- package/docs/documentation/imageIo.js.html +291 -0
- package/docs/documentation/imageLayers.js.html +188 -0
- package/docs/documentation/imageLoading.js.html +297 -0
- package/docs/documentation/imageParsing.js.html +385 -0
- package/docs/documentation/imagePresets.js.html +207 -0
- package/docs/documentation/imageRendering.js.html +849 -0
- package/docs/documentation/imageReslice.js.html +162 -0
- package/docs/documentation/imageStore.js.html +360 -0
- package/docs/documentation/imageTools.js.html +784 -0
- package/docs/documentation/imageUtils.js.html +1609 -0
- package/docs/documentation/image_colormaps.js.html +283 -0
- package/docs/documentation/image_contours.js.html +279 -0
- package/docs/documentation/image_io.js.html +288 -0
- package/docs/documentation/image_layers.js.html +188 -0
- package/docs/documentation/image_loading.js.html +294 -0
- package/docs/documentation/image_parsing.js.html +391 -0
- package/docs/documentation/image_presets.js.html +207 -0
- package/docs/documentation/image_rendering.js.html +845 -0
- package/docs/documentation/image_reslice.js.html +164 -0
- package/docs/documentation/image_store.js.html +359 -0
- package/docs/documentation/image_tools.js.html +792 -0
- package/docs/documentation/image_utils.js.html +1609 -0
- package/docs/documentation/index.html +175 -0
- package/docs/documentation/loaders_commonLoader.js.html +306 -0
- package/docs/documentation/loaders_dicomLoader.js.html +130 -0
- package/docs/documentation/loaders_fileLoader.js.html +155 -0
- package/docs/documentation/loaders_multiframeLoader.js.html +443 -0
- package/docs/documentation/loaders_niftiLoader.js.html +150 -0
- package/docs/documentation/loaders_nrrdLoader.js.html +545 -0
- package/docs/documentation/loaders_resliceLoader.js.html +258 -0
- package/docs/documentation/module-imaging_contours.html +954 -0
- package/docs/documentation/module-imaging_imageAnonymization.html +544 -0
- package/docs/documentation/module-imaging_imageColormaps.html +1012 -0
- package/docs/documentation/module-imaging_imageContours.html +954 -0
- package/docs/documentation/module-imaging_imageIo.html +1057 -0
- package/docs/documentation/module-imaging_imageLayers.html +904 -0
- package/docs/documentation/module-imaging_imageLoading.html +1301 -0
- package/docs/documentation/module-imaging_imageParsing.html +1356 -0
- package/docs/documentation/module-imaging_imagePresets.html +679 -0
- package/docs/documentation/module-imaging_imageRendering.html +3223 -0
- package/docs/documentation/module-imaging_imageReslice.html +413 -0
- package/docs/documentation/module-imaging_imageStore-Larvitar_Store.html +284 -0
- package/docs/documentation/module-imaging_imageStore.html +1560 -0
- package/docs/documentation/module-imaging_imageTools.html +3617 -0
- package/docs/documentation/module-imaging_imageUtils.html +7253 -0
- package/docs/documentation/module-imaging_io.html +1057 -0
- package/docs/documentation/module-imaging_layers.html +904 -0
- package/docs/documentation/module-imaging_loading.html +1301 -0
- package/docs/documentation/module-imaging_parsing.html +1375 -0
- package/docs/documentation/module-imaging_presets.html +679 -0
- package/docs/documentation/module-imaging_rendering.html +8094 -0
- package/docs/documentation/module-imaging_reslice.html +411 -0
- package/docs/documentation/module-imaging_store-Larvitar_Store.html +284 -0
- package/docs/documentation/module-imaging_store.html +1537 -0
- package/docs/documentation/module-imaging_strategies_eraseFreehand.html +708 -0
- package/docs/documentation/module-imaging_strategies_fillFreehand.html +708 -0
- package/docs/documentation/module-imaging_tools.html +3617 -0
- package/docs/documentation/module-imaging_tools_custom_contourTool.html +207 -0
- package/docs/documentation/module-imaging_tools_custom_diameterTool.html +205 -0
- package/docs/documentation/module-imaging_tools_custom_editMaskTool.html +205 -0
- package/docs/documentation/module-imaging_tools_custom_polygonScissorsTool.html +203 -0
- package/docs/documentation/module-imaging_tools_custom_thresholdBrushTool.html +684 -0
- package/docs/documentation/module-imaging_tools_default.html +205 -0
- package/docs/documentation/module-imaging_tools_interaction.html +530 -0
- package/docs/documentation/module-imaging_tools_io.html +832 -0
- package/docs/documentation/module-imaging_tools_main.html +2028 -0
- package/docs/documentation/module-imaging_tools_polygonSegmentationMixin.html +567 -0
- package/docs/documentation/module-imaging_tools_segmentation.html +3586 -0
- package/docs/documentation/module-imaging_tools_state.html +494 -0
- package/docs/documentation/module-imaging_utils.html +7253 -0
- package/docs/documentation/module-loaders_commonLoader.html +1313 -0
- package/docs/documentation/module-loaders_dicomLoader.html +522 -0
- package/docs/documentation/module-loaders_fileLoader.html +593 -0
- package/docs/documentation/module-loaders_multiframeLoader.html +1169 -0
- package/docs/documentation/module-loaders_niftiLoader.html +565 -0
- package/docs/documentation/module-loaders_nrrdLoader.html +1459 -0
- package/docs/documentation/module-loaders_resliceLoader.html +590 -0
- package/docs/documentation/module-monitors_memory.html +980 -0
- package/docs/documentation/module-tools_default.html +740 -0
- package/docs/documentation/module.exports_module.exports.html +203 -0
- package/docs/documentation/monitors_memory.js.html +189 -0
- package/docs/documentation/parsers_nrrd.js.html +569 -0
- package/docs/documentation/scripts/collapse.js +20 -0
- package/docs/documentation/scripts/linenumber.js +25 -0
- package/docs/documentation/scripts/nav.js +12 -0
- package/docs/documentation/scripts/polyfill.js +4 -0
- package/docs/documentation/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/docs/documentation/scripts/prettify/lang-css.js +2 -0
- package/docs/documentation/scripts/prettify/prettify.js +28 -0
- package/docs/documentation/scripts/search.js +83 -0
- package/docs/documentation/styles/jsdoc.css +765 -0
- package/docs/documentation/styles/prettify.css +80 -0
- package/docs/documentation/tools_contourTool.js.html +1963 -0
- package/docs/documentation/tools_custom_contourTool.js.html +1968 -0
- package/docs/documentation/tools_custom_diameterTool.js.html +225 -0
- package/docs/documentation/tools_custom_editMaskTool.js.html +225 -0
- package/docs/documentation/tools_custom_polylineScissorsTool.js.html +143 -0
- package/docs/documentation/tools_custom_thresholdsBrushTool.js.html +245 -0
- package/docs/documentation/tools_default.js.html +576 -0
- package/docs/documentation/tools_diameterTool.js.html +219 -0
- package/docs/documentation/tools_editMaskTool.js.html +219 -0
- package/docs/documentation/tools_interaction.js.html +258 -0
- package/docs/documentation/tools_io.js.html +297 -0
- package/docs/documentation/tools_main.js.html +443 -0
- package/docs/documentation/tools_polygonSegmentationMixin.js.html +329 -0
- package/docs/documentation/tools_polylineScissorsTool.js.html +136 -0
- package/docs/documentation/tools_seedTool.js.html +423 -0
- package/docs/documentation/tools_segmentation.js.html +558 -0
- package/docs/documentation/tools_state.js.html +163 -0
- package/docs/documentation/tools_strategies_eraseFreehand.js.html +160 -0
- package/docs/documentation/tools_strategies_fillFreehand.js.html +163 -0
- package/docs/documentation/tools_thresholdsBrushTool.js.html +239 -0
- package/docs/documentation/tools_tools.default.js.html +569 -0
- package/docs/documentation/tools_tools.interaction.js.html +251 -0
- package/docs/documentation/tools_tools.io.js.html +288 -0
- package/docs/documentation/tools_tools.main.js.html +442 -0
- package/docs/documentation/tools_tools.segmentation.js.html +445 -0
- package/docs/documentation/tools_tools.state.js.html +157 -0
- package/docs/examples/base.html +170 -0
- package/docs/examples/colorMaps.html +181 -0
- package/docs/examples/defaultTools.html +246 -0
- package/docs/examples/demo/anon1 +0 -0
- package/docs/examples/demo/anon10 +0 -0
- package/docs/examples/demo/anon11 +0 -0
- package/docs/examples/demo/anon12 +0 -0
- package/docs/examples/demo/anon13 +0 -0
- package/docs/examples/demo/anon14 +0 -0
- package/docs/examples/demo/anon15 +0 -0
- package/docs/examples/demo/anon16 +0 -0
- package/docs/examples/demo/anon17 +0 -0
- package/docs/examples/demo/anon18 +0 -0
- package/docs/examples/demo/anon19 +0 -0
- package/docs/examples/demo/anon2 +0 -0
- package/docs/examples/demo/anon20 +0 -0
- package/docs/examples/demo/anon21 +0 -0
- package/docs/examples/demo/anon22 +0 -0
- package/docs/examples/demo/anon23 +0 -0
- package/docs/examples/demo/anon24 +0 -0
- package/docs/examples/demo/anon3 +0 -0
- package/docs/examples/demo/anon4 +0 -0
- package/docs/examples/demo/anon5 +0 -0
- package/docs/examples/demo/anon6 +0 -0
- package/docs/examples/demo/anon7 +0 -0
- package/docs/examples/demo/anon8 +0 -0
- package/docs/examples/demo/anon9 +0 -0
- package/docs/examples/demo/example.nrrd +0 -0
- package/docs/examples/demo/segmentation.nrrd +0 -0
- package/docs/examples/demo/xa_integris.dcm +0 -0
- package/docs/examples/index.html +129 -0
- package/docs/examples/larvitar.js +108623 -0
- package/docs/examples/layers.html +250 -0
- package/docs/examples/masks.html +273 -0
- package/docs/examples/multiframe.html +200 -0
- package/docs/examples/nrrd.html +96 -0
- package/docs/examples/reslice.html +174 -0
- package/docs/index.html +92 -0
- package/imaging/dataDictionary.json +21865 -21865
- package/imaging/imageAnonymization.js +161 -0
- package/imaging/{image_colormaps.js → imageColormaps.js} +2 -2
- package/imaging/{image_contours.js → imageContours.js} +1 -2
- package/imaging/{image_io.js → imageIo.js} +18 -15
- package/imaging/{image_layers.js → imageLayers.js} +2 -2
- package/imaging/{image_loading.js → imageLoading.js} +9 -6
- package/imaging/imageParsing.js +301 -0
- package/imaging/{image_presets.js → imagePresets.js} +2 -2
- package/imaging/{image_rendering.js → imageRendering.js} +36 -32
- package/imaging/imageReslice.js +78 -0
- package/imaging/{image_store.js → imageStore.js} +8 -7
- package/imaging/{image_tools.js → imageTools.js} +15 -23
- package/imaging/{image_utils.js → imageUtils.js} +1 -1
- package/imaging/loaders/commonLoader.js +1 -1
- package/imaging/loaders/dicomLoader.js +1 -1
- package/imaging/loaders/fileLoader.js +2 -2
- package/imaging/loaders/multiframeLoader.js +6 -2
- package/imaging/loaders/nrrdLoader.js +11 -7
- package/imaging/tools/{contourTool.js → custom/contourTool.js} +25 -20
- package/imaging/tools/{diameterTool.js → custom/diameterTool.js} +9 -3
- package/imaging/tools/{editMaskTool.js → custom/editMaskTool.js} +7 -1
- package/imaging/tools/{polylineScissorsTool.js → custom/polylineScissorsTool.js} +12 -5
- package/imaging/tools/{seedTool.js → custom/seedTool.js} +3 -3
- package/imaging/tools/{thresholdsBrushTool.js → custom/thresholdsBrushTool.js} +7 -1
- package/imaging/tools/{tools.default.js → default.js} +10 -3
- package/imaging/tools/{tools.interaction.js → interaction.js} +13 -6
- package/imaging/tools/{tools.io.js → io.js} +15 -6
- package/imaging/tools/{tools.main.js → main.js} +16 -14
- package/imaging/tools/polygonSegmentationMixin.js +8 -4
- package/imaging/tools/{tools.segmentation.js → segmentation.js} +171 -58
- package/imaging/tools/segmentations.md +38 -0
- package/imaging/tools/setLabelMap3D.js +248 -0
- package/imaging/tools/{tools.state.js → state.js} +7 -1
- package/imaging/tools/strategies/eraseFreehand.js +8 -9
- package/imaging/tools/strategies/fillFreehand.js +8 -9
- package/index.js +44 -39
- package/modules/vuex/larvitar.js +13 -3
- package/package.json +13 -10
- package/imaging/image_parsing.js +0 -307
- package/imaging/image_reslice.js +0 -80
|
@@ -0,0 +1,1609 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
<title>image_utils.js - Larvitar</title>
|
|
7
|
+
|
|
8
|
+
<meta name="description" content="Dicom Image Toolkit for CornestoneJS" />
|
|
9
|
+
|
|
10
|
+
<meta name="keywords" content="imaging, dataviz, medical, cornerstone" />
|
|
11
|
+
<meta name="keyword" content="imaging, dataviz, medical, cornerstone" />
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
<script src="scripts/prettify/prettify.js"></script>
|
|
16
|
+
<script src="scripts/prettify/lang-css.js"></script>
|
|
17
|
+
<!--[if lt IE 9]>
|
|
18
|
+
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
19
|
+
<![endif]-->
|
|
20
|
+
<link type="text/css" rel="stylesheet" href="styles/prettify.css">
|
|
21
|
+
<link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
|
|
22
|
+
<script src="scripts/nav.js" defer></script>
|
|
23
|
+
|
|
24
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
25
|
+
</head>
|
|
26
|
+
<body>
|
|
27
|
+
|
|
28
|
+
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
|
|
29
|
+
<label for="nav-trigger" class="navicon-button x">
|
|
30
|
+
<div class="navicon"></div>
|
|
31
|
+
</label>
|
|
32
|
+
|
|
33
|
+
<label for="nav-trigger" class="overlay"></label>
|
|
34
|
+
|
|
35
|
+
<nav >
|
|
36
|
+
|
|
37
|
+
<input type="text" id="nav-search" placeholder="Search" />
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
<h2><a href="index.html">Home</a></h2><h2><a href="https://github.com/dvisionlab/Larvitar" target="_blank" class="menu-item" id="repository" >Github repo</a></h2><h3>Classes</h3><ul><li><a href="module.exports_module.exports.html">module.exports#module.exports</a></li><li><a href="module-imaging_store-Larvitar_Store.html">imaging/store~Larvitar_Store</a></li><li><a href="Tools.Annotation.ContoursTool.html">Tools.Annotation.ContoursTool</a></li><li><a href="Tools.Annotation.DiameterTool.html">Tools.Annotation.DiameterTool</a></li><li><a href="Tools.Brush.BrushTool.html">Tools.Brush.BrushTool</a></li><li><a href="Tools.Brush.ThresholdsBrushTool.html">Tools.Brush.ThresholdsBrushTool</a></li><li><a href="Tools.PolylineScissorsTool.html">Tools.PolylineScissorsTool</a></li></ul><h3>Modules</h3><ul><li><a href="module-imaging_anonymization.html">imaging/anonymization</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_anonymization.html#anonymize#~anonymize">anonymize</a></li><li data-type='method' style='display: none;'><a href="module-imaging_anonymization.html#encrypt#~encrypt">encrypt</a></li></ul></li><li><a href="module-imaging_contours.html">imaging/contours</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_contours.html#extractSlicePoints#extractSlicePoints">extractSlicePoints</a></li><li data-type='method' style='display: none;'><a href="module-imaging_contours.html#populateContoursObject#populateContoursObject">populateContoursObject</a></li><li data-type='method' style='display: none;'><a href="module-imaging_contours.html#parseContours#~parseContours">parseContours</a></li></ul></li><li><a href="module-imaging_io.html">imaging/io</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_io.html#buildData#~buildData">buildData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#buildDataAsync#~buildDataAsync">buildDataAsync</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#buildHeader#~buildHeader">buildHeader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#getCachedPixelData#~getCachedPixelData">getCachedPixelData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_io.html#importNRRDImage#~importNRRDImage">importNRRDImage</a></li></ul></li><li><a href="module-imaging_layers.html">imaging/layers</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#getActiveLayer#getActiveLayer">getActiveLayer</a></li><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#setActiveLayer#setActiveLayer">setActiveLayer</a></li><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#updateLayer#updateLayer">updateLayer</a></li><li data-type='method' style='display: none;'><a href="module-imaging_layers.html#buildLayers#~buildLayers">buildLayers</a></li></ul></li><li><a href="module-imaging_loading.html">imaging/loading</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#initializeFileImageLoader#initializeFileImageLoader">initializeFileImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#initializeImageLoader#initializeImageLoader">initializeImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#initializeWebImageLoader#initializeWebImageLoader">initializeWebImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#registerMultiFrameImageLoader#registerMultiFrameImageLoader">registerMultiFrameImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#registerNRRDImageLoader#registerNRRDImageLoader">registerNRRDImageLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#registerResliceLoader#registerResliceLoader">registerResliceLoader</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#updateLoadedStack#updateLoadedStack">updateLoadedStack</a></li><li data-type='method' style='display: none;'><a href="module-imaging_loading.html#isNewInstance#~isNewInstance">isNewInstance</a></li></ul></li><li><a href="module-imaging_parsing.html">imaging/parsing</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#clearImageParsing#clearImageParsing">clearImageParsing</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#dumpDataSet#dumpDataSet">dumpDataSet</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#readFile#readFile">readFile</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#readFiles#readFiles">readFiles</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#dumpFile#~dumpFile">dumpFile</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#dumpFiles#~dumpFiles">dumpFiles</a></li><li data-type='method' style='display: none;'><a href="module-imaging_parsing.html#parseNextFile#~parseNextFile">parseNextFile</a></li></ul></li><li><a href="module-imaging_presets.html">imaging/presets</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_presets.html#getImagePresets#getImagePresets">getImagePresets</a></li><li data-type='method' style='display: none;'><a href="module-imaging_presets.html#setImageCustomPreset#setImageCustomPreset">setImageCustomPreset</a></li><li data-type='method' style='display: none;'><a href="module-imaging_presets.html#setImagePreset#setImagePreset">setImagePreset</a></li></ul></li><li><a href="module-imaging_rendering.html">imaging/rendering</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#HSVToRGB#.HSVToRGB">HSVToRGB</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#addColorMap#addColorMap">addColorMap</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#applyColorMap#applyColorMap">applyColorMap</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#clearImageCache#clearImageCache">clearImageCache</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#disableViewport#disableViewport">disableViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#fillPixelData#fillPixelData">fillPixelData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#flipImageHorizontal#flipImageHorizontal">flipImageHorizontal</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#flipImageVertical#flipImageVertical">flipImageVertical</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#getColormapsList#getColormapsList">getColormapsList</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#getSeriesData#getSeriesData">getSeriesData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#invertImage#invertImage">invertImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#loadAndCacheImages#loadAndCacheImages">loadAndCacheImages</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#renderImage#renderImage">renderImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#renderWebImage#renderWebImage">renderWebImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#renderWebImage#renderWebImage">renderWebImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#resetViewports#resetViewports">resetViewports</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#resizeViewport#resizeViewport">resizeViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#rotateImageLeft#rotateImageLeft">rotateImageLeft</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#rotateImageRight#rotateImageRight">rotateImageRight</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#storeViewportData#storeViewportData">storeViewportData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#unloadViewport#unloadViewport">unloadViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#updateImage#updateImage">updateImage</a></li><li data-type='method' style='display: none;'><a href="module-imaging_rendering.html#updateViewportData#updateViewportData">updateViewportData</a></li></ul></li><li></li><li><a href="module-imaging_reslice.html">imaging/reslice</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_reslice.html#resliceSeries#resliceSeries">resliceSeries</a></li></ul></li><li><a href="module-imaging_store.html">imaging/store</a><ul class='members'><li data-type='member' style='display: none;'><a href="module-imaging_store.html#.larvitar_store">larvitar_store</a></li></ul><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_store.html#initLarvitarStore#.initLarvitarStore">initLarvitarStore</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#addSeriesIds#~addSeriesIds">addSeriesIds</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#addViewport#~addViewport">addViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#deleteViewport#~deleteViewport">deleteViewport</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#disableVuex#~disableVuex">disableVuex</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#enableVuex#~enableVuex">enableVuex</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#get#~get">get</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#removeSeriesIds#~removeSeriesIds">removeSeriesIds</a></li><li data-type='method' style='display: none;'><a href="module-imaging_store.html#set#~set">set</a></li></ul></li><li><a href="module-imaging_tools.html">imaging/tools</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addContoursTool#~addContoursTool">addContoursTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addDefaultTools#~addDefaultTools">addDefaultTools</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addDiameterTool#~addDiameterTool">addDiameterTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addMaskEditingTool#~addMaskEditingTool">addMaskEditingTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addSeedsTool#~addSeedsTool">addSeedsTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addStackStateToElement#~addStackStateToElement">addStackStateToElement</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#addToolStateSingleSlice#~addToolStateSingleSlice">addToolStateSingleSlice</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#clearCornerstoneElements#~clearCornerstoneElements">clearCornerstoneElements</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#clearMeasurements#~clearMeasurements">clearMeasurements</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#clearToolStateByName#~clearToolStateByName">clearToolStateByName</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#getCurrentMaskData#~getCurrentMaskData">getCurrentMaskData</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#getToolState#~getToolState">getToolState</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#isToolMissing#~isToolMissing">isToolMissing</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setSegmentationConfig#~setSegmentationConfig">setSegmentationConfig</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolActive#~setToolActive">setToolActive</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolActive#~setToolActive">setToolActive</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolEnabled#~setToolEnabled">setToolEnabled</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#setToolPassive#~setToolPassive">setToolPassive</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#syncToolStack#~syncToolStack">syncToolStack</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#updateDiameterTool#~updateDiameterTool">updateDiameterTool</a></li><li data-type='method' style='display: none;'><a href="module-imaging_tools.html#updateStackToolState#~updateStackToolState">updateStackToolState</a></li></ul></li><li><a href="module-imaging_utils.html">imaging/utils</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#formatDate#formatDate">formatDate</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#formatDateTime#formatDateTime">formatDateTime</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getCmprMetadata#getCmprMetadata">getCmprMetadata</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getDICOMTag#getDICOMTag">getDICOMTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getDICOMTagCode#getDICOMTagCode">getDICOMTagCode</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getDistanceBetweenSlices#getDistanceBetweenSlices">getDistanceBetweenSlices</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getMaxPixelValue#getMaxPixelValue">getMaxPixelValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getMeanValue#getMeanValue">getMeanValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getMinPixelValue#getMinPixelValue">getMinPixelValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getNormalOrientation#getNormalOrientation">getNormalOrientation</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getPixelRepresentation#getPixelRepresentation">getPixelRepresentation</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getPixelTypedArray#getPixelTypedArray">getPixelTypedArray</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedIOP#getReslicedIOP">getReslicedIOP</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedIPP#getReslicedIPP">getReslicedIPP</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedMetadata#getReslicedMetadata">getReslicedMetadata</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedPixeldata#getReslicedPixeldata">getReslicedPixeldata</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getReslicedSliceLocation#getReslicedSliceLocation">getReslicedSliceLocation</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getSortedStack#getSortedStack">getSortedStack</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getSortedUIDs#getSortedUIDs">getSortedUIDs</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getTagValue#getTagValue">getTagValue</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getTypedArray#getTypedArray">getTypedArray</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#getTypedArrayFromDataType#getTypedArrayFromDataType">getTypedArrayFromDataType</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isElement#isElement">isElement</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isNegativeSign#isNegativeSign">isNegativeSign</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isStringVr#isStringVr">isStringVr</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#isValidDate#isValidDate">isValidDate</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseAgeTag#parseAgeTag">parseAgeTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseDateTag#parseDateTag">parseDateTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseDateTimeTag#parseDateTimeTag">parseDateTimeTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseDICOMFileIDTag#parseDICOMFileIDTag">parseDICOMFileIDTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parsePatientNameTag#parsePatientNameTag">parsePatientNameTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseTag#parseTag">parseTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#parseTimeTag#parseTimeTag">parseTimeTag</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#permuteSignedArrays#permuteSignedArrays">permuteSignedArrays</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#permuteValues#permuteValues">permuteValues</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#rand#rand">rand</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#randomId#randomId">randomId</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#sortStackCallback#sortStackCallback">sortStackCallback</a></li><li data-type='method' style='display: none;'><a href="module-imaging_utils.html#spacingArray#spacingArray">spacingArray</a></li></ul></li><li><a href="module-loaders_commonLoader.html">loaders/commonLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getImageFrame#getImageFrame">getImageFrame</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getLarvitarImageTracker#getLarvitarImageTracker">getLarvitarImageTracker</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getLarvitarManager#getLarvitarManager">getLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#getSeriesDataFromLarvitarManager#getSeriesDataFromLarvitarManager">getSeriesDataFromLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#populateLarvitarManager#populateLarvitarManager">populateLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#removeSeriesFromLarvitarManager#removeSeriesFromLarvitarManager">removeSeriesFromLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#resetLarvitarManager#resetLarvitarManager">resetLarvitarManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_commonLoader.html#updateLarvitarManager#updateLarvitarManager">updateLarvitarManager</a></li></ul></li><li><a href="module-loaders_dicomLoader.html">loaders/dicomLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_dicomLoader.html#cacheImages#cacheImages">cacheImages</a></li><li data-type='method' style='display: none;'><a href="module-loaders_dicomLoader.html#getDicomImageId#getDicomImageId">getDicomImageId</a></li></ul></li><li><a href="module-loaders_fileLoader.html">loaders/fileLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#getFileImageId#getFileImageId">getFileImageId</a></li><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#populateFileManager#populateFileManager">populateFileManager</a></li><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#resetFileLoader#resetFileLoader">resetFileLoader</a></li><li data-type='method' style='display: none;'><a href="module-loaders_fileLoader.html#resetFileManager#resetFileManager">resetFileManager</a></li></ul></li><li><a href="module-loaders_nrrdLoader.html">loaders/nrrdLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#buildNrrdImage#buildNrrdImage">buildNrrdImage</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#createCustomImage#createCustomImage">createCustomImage</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getImageIdFromSlice#getImageIdFromSlice">getImageIdFromSlice</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getNrrdImageId#getNrrdImageId">getNrrdImageId</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getNrrdSerieDimensions#getNrrdSerieDimensions">getNrrdSerieDimensions</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#getSliceNumberFromImageId#getSliceNumberFromImageId">getSliceNumberFromImageId</a></li><li data-type='method' style='display: none;'><a href="module-loaders_nrrdLoader.html#loadNrrdImage#loadNrrdImage">loadNrrdImage</a></li></ul></li><li><a href="module-loaders_resliceLoader.html">loaders/resliceLoader</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-loaders_resliceLoader.html#createCustomImage#createCustomImage">createCustomImage</a></li><li data-type='method' style='display: none;'><a href="module-loaders_resliceLoader.html#loadReslicedImage#loadReslicedImage">loadReslicedImage</a></li></ul></li><li><a href="module-monitors_memory.html">monitors/memory</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#checkMemoryAllocation#checkMemoryAllocation">checkMemoryAllocation</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#checkMemorySupport#checkMemorySupport">checkMemorySupport</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#getAvailableMemory#getAvailableMemory">getAvailableMemory</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#getMB#getMB">getMB</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#getUsedMemory#getUsedMemory">getUsedMemory</a></li><li data-type='method' style='display: none;'><a href="module-monitors_memory.html#setAvailableMemory#setAvailableMemory">setAvailableMemory</a></li></ul></li><li><a href="module-tools_default.html">tools/default</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-tools_default.html#getDefaultToolsByType#~getDefaultToolsByType">getDefaultToolsByType</a></li><li data-type='method' style='display: none;'><a href="module-tools_default.html#setDefaultToolsProps#~setDefaultToolsProps">setDefaultToolsProps</a></li></ul></li></ul><h3>Events</h3><ul><li><a href="ContoursTool.html#event:_drawingDoubleTapClickCallback">ContoursTool#_drawingDoubleTapClickCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseDoubleClickCallback">ContoursTool#_drawingMouseDoubleClickCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseDownCallback">ContoursTool#_drawingMouseDownCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseDragCallback">ContoursTool#_drawingMouseDragCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseMoveCallback">ContoursTool#_drawingMouseMoveCallback</a></li><li><a href="ContoursTool.html#event:_drawingMouseUpCallback">ContoursTool#_drawingMouseUpCallback</a></li><li><a href="ContoursTool.html#event:_drawingTouchDragCallback">ContoursTool#_drawingTouchDragCallback</a></li><li><a href="ContoursTool.html#event:_drawingTouchStartCallback">ContoursTool#_drawingTouchStartCallback</a></li><li><a href="ContoursTool.html#event:_editMouseDragCallback">ContoursTool#_editMouseDragCallback</a></li><li><a href="ContoursTool.html#event:_editTouchDragCallback">ContoursTool#_editTouchDragCallback</a></li></ul><h3>Mixins</h3><ul><li><a href="Mixins.polygonSegmentationMixin%2520-%2520segmentation%2520operations%2520for%2520polyline.html">Mixins.polygonSegmentationMixin - segmentation operations for polyline</a></li></ul><h3>Global</h3><ul><li><a href="global.html#_checkIfDrawing">_checkIfDrawing</a></li><li><a href="global.html#_paint">_paint</a></li><li><a href="global.html#addDefaultTools">addDefaultTools</a></li><li><a href="global.html#addMouseKeyHandlers">addMouseKeyHandlers</a></li><li><a href="global.html#addSegmentationMask">addSegmentationMask</a></li><li><a href="global.html#addTool">addTool</a></li><li><a href="global.html#buildMultiFrameImage">buildMultiFrameImage</a></li><li><a href="global.html">clearMultiFrameCache</a></li><li><a href="global.html#clearSegmentationState">clearSegmentationState</a></li><li><a href="global.html#config">config</a></li><li><a href="global.html">createCustomImage</a></li><li><a href="global.html#csToolsCreateStack">csToolsCreateStack</a></li><li><a href="global.html#csToolsUpdateImageIndex">csToolsUpdateImageIndex</a></li><li><a href="global.html#deleteMask">deleteMask</a></li><li><a href="global.html#disableBrushTool">disableBrushTool</a></li><li><a href="global.html#download">download</a></li><li><a href="global.html#enableBrushTool">enableBrushTool</a></li><li><a href="global.html#eraseFreehand">eraseFreehand</a></li><li><a href="global.html#eraseInsideFreehand">eraseInsideFreehand</a></li><li><a href="global.html#eraseOutsideFreehand">eraseOutsideFreehand</a></li><li><a href="global.html#exportAnnotations">exportAnnotations</a></li><li><a href="global.html#extractToolInfo">extractToolInfo</a></li><li><a href="global.html#fillFreehand">fillFreehand</a></li><li><a href="global.html#fillInsideFreehand">fillInsideFreehand</a></li><li><a href="global.html#fillOutsideFreehand">fillOutsideFreehand</a></li><li><a href="global.html#forceRender">forceRender</a></li><li><a href="global.html#generateCSV">generateCSV</a></li><li><a href="global.html#generateLUT">generateLUT</a></li><li><a href="global.html#generateUniformLUT">generateUniformLUT</a></li><li><a href="global.html#getActiveLabelmapBuffer">getActiveLabelmapBuffer</a></li><li><a href="global.html#getCircleWithThreshold">getCircleWithThreshold</a></li><li><a href="global.html">getMultiFrameImageId</a></li><li><a href="global.html#HSVtoRGB">HSVtoRGB</a></li><li><a href="global.html#initializeCSTools">initializeCSTools</a></li><li><a href="global.html#initSegmentationModule">initSegmentationModule</a></li><li><a href="global.html#isDrawing">isDrawing</a></li><li><a href="global.html#isToolMissing">isToolMissing</a></li><li><a href="global.html#loadAnnotations">loadAnnotations</a></li><li><a href="global.html#loadMultiFrameImage">loadMultiFrameImage</a></li><li><a href="global.html#NRRD_TYPES_TO_TYPEDARRAY">NRRD_TYPES_TO_TYPEDARRAY</a></li><li><a href="global.html">parse</a></li><li><a href="global.html#redoLastStroke">redoLastStroke</a></li><li><a href="global.html#renderToolData">renderToolData</a></li><li><a href="global.html#restoreToolState">restoreToolState</a></li><li><a href="global.html#saveAnnotations">saveAnnotations</a></li><li><a href="global.html#saveToolState">saveToolState</a></li><li><a href="global.html#setActiveLabelmap">setActiveLabelmap</a></li><li><a href="global.html#setActiveLabelOpacity">setActiveLabelOpacity</a></li><li><a href="global.html#setActiveSegment">setActiveSegment</a></li><li><a href="global.html#setBrushProps">setBrushProps</a></li><li><a href="global.html#setInactiveLabelOpacity">setInactiveLabelOpacity</a></li><li><a href="global.html#setMaskProps">setMaskProps</a></li><li><a href="global.html">setPixelDataType</a></li><li><a href="global.html#setToolActive">setToolActive</a></li><li><a href="global.html#setToolDisabled">setToolDisabled</a></li><li><a href="global.html#setToolEnabled">setToolEnabled</a></li><li><a href="global.html#setToolPassive">setToolPassive</a></li><li><a href="global.html#setToolsStyle">setToolsStyle</a></li><li><a href="global.html#toggleContourMode">toggleContourMode</a></li><li><a href="global.html">toggleMouseHandlers</a></li><li><a href="global.html#tryUpdateImage">tryUpdateImage</a></li><li><a href="global.html#undoLastStroke">undoLastStroke</a></li></ul>
|
|
41
|
+
|
|
42
|
+
</nav>
|
|
43
|
+
|
|
44
|
+
<div id="main">
|
|
45
|
+
|
|
46
|
+
<h1 class="page-title">image_utils.js</h1>
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
<section>
|
|
55
|
+
<article>
|
|
56
|
+
<pre class="prettyprint source linenums"><code>/** @module imaging/utils
|
|
57
|
+
* @desc This file provides utility functions for
|
|
58
|
+
* manipulating image pixels and image metadata
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
// external libraries
|
|
62
|
+
import {
|
|
63
|
+
isEmpty,
|
|
64
|
+
sortBy,
|
|
65
|
+
clone,
|
|
66
|
+
find,
|
|
67
|
+
has,
|
|
68
|
+
max,
|
|
69
|
+
map,
|
|
70
|
+
forEach,
|
|
71
|
+
extend,
|
|
72
|
+
indexOf,
|
|
73
|
+
random
|
|
74
|
+
} from "lodash";
|
|
75
|
+
import { v4 as uuidv4 } from "uuid";
|
|
76
|
+
import cornerstone from "cornerstone-core";
|
|
77
|
+
import { convertBytes } from "dicom-character-set";
|
|
78
|
+
|
|
79
|
+
// internal libraries
|
|
80
|
+
import { getDicomImageId } from "./loaders/dicomLoader";
|
|
81
|
+
import TAG_DICT from "./dataDictionary.json";
|
|
82
|
+
|
|
83
|
+
// global module variables
|
|
84
|
+
// variables used to manage the reslice functionality
|
|
85
|
+
const resliceTable = {
|
|
86
|
+
sagittal: { coronal: [-2, 1, 0], axial: [-2, 0, -1] },
|
|
87
|
+
coronal: { sagittal: [2, 1, -0], axial: [0, 2, -1] },
|
|
88
|
+
axial: { sagittal: [1, -2, -0], coronal: [0, -2, 1] }
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* This module provides the following functions to be exported:
|
|
93
|
+
* getNormalOrientation(array[6])
|
|
94
|
+
* getMinPixelValue(defaultValue, pixelData)
|
|
95
|
+
* getMaxPixelValue(defaultValue, pixelData)
|
|
96
|
+
* getPixelRepresentation(dataset)
|
|
97
|
+
* getTypedArrayFromDataType(dataType)
|
|
98
|
+
* getPixelTypedArray(dataset, pixelDataElement)
|
|
99
|
+
* getSortedStack(seriesData, sortPriorities, returnSuccessMethod)
|
|
100
|
+
* getSortedUIDs(seriesData)
|
|
101
|
+
* randomId()
|
|
102
|
+
* getMeanValue(series, tag, isArray)
|
|
103
|
+
* getReslicedMetadata(reslicedSeriesId, fromOrientation, toOrientation, seriesData, imageLoaderName)
|
|
104
|
+
* getCmprMetadata(reslicedSeriesId, imageLoaderName, header)
|
|
105
|
+
* getReslicedPixeldata(imageId, originalData, reslicedData)
|
|
106
|
+
* getDistanceBetweenSlices(seriesData, sliceIndex1, sliceIndex2)
|
|
107
|
+
* parseTag(dataSet, propertyName, element)
|
|
108
|
+
* isElement(o)
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @typedef {Object} CornerstoneSeries
|
|
113
|
+
* @property {Array} imageIds Array of the instances imageIds
|
|
114
|
+
* @property {Array} instances Array of instances
|
|
115
|
+
* @property {Number} currentImageIndex Currently loaded image id index in the imageIds array
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Return computed 3D normal from two 3D vectors
|
|
120
|
+
* @instance
|
|
121
|
+
* @function getNormalOrientation
|
|
122
|
+
* @param {Array} el - The image_orientation dicom tag
|
|
123
|
+
*/
|
|
124
|
+
export const getNormalOrientation = function (el) {
|
|
125
|
+
let a = [el[0], el[1], el[2]];
|
|
126
|
+
let b = [el[3], el[4], el[5]];
|
|
127
|
+
|
|
128
|
+
let n = [
|
|
129
|
+
a[1] * b[2] - a[2] * b[1],
|
|
130
|
+
a[2] * b[0] - a[0] * b[2],
|
|
131
|
+
a[0] * b[1] - a[1] * b[0]
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
return n;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* If a value is provided, returns it, otherwise get the min pixel value from pixelData
|
|
139
|
+
* @instance
|
|
140
|
+
* @function getMinPixelValue
|
|
141
|
+
* @param {Number} value - The min value
|
|
142
|
+
* @param {Array} pixelData - Pixel data array
|
|
143
|
+
*/
|
|
144
|
+
export const getMinPixelValue = function (value, pixelData) {
|
|
145
|
+
if (value !== undefined) {
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
let min;
|
|
149
|
+
for (let i = 0; i < pixelData.length; i++) {
|
|
150
|
+
if (!min || min > pixelData[i]) {
|
|
151
|
+
min = pixelData[i];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return min;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* If a value is provided, returns it, otherwise get the max pixel value from pixelData
|
|
159
|
+
* @instance
|
|
160
|
+
* @function getMaxPixelValue
|
|
161
|
+
* @param {Number} value - The max value
|
|
162
|
+
* @param {Array} pixelData - Pixel data array
|
|
163
|
+
*/
|
|
164
|
+
export const getMaxPixelValue = function (value, pixelData) {
|
|
165
|
+
if (value !== undefined) {
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let max;
|
|
170
|
+
for (let i = 0; i < pixelData.length; i++) {
|
|
171
|
+
if (!max || max < pixelData[i]) {
|
|
172
|
+
max = pixelData[i];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return max;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Create the pixel representation string (type and length) from dicom tags
|
|
180
|
+
* @instance
|
|
181
|
+
* @function getPixelRepresentation
|
|
182
|
+
* @param {Object} dataSet - The dataset
|
|
183
|
+
* @returns {String} The pixel representation in the form Sint / Uint + bytelength
|
|
184
|
+
*/
|
|
185
|
+
export const getPixelRepresentation = function (dataSet) {
|
|
186
|
+
if (dataSet.repr) {
|
|
187
|
+
return dataSet.repr;
|
|
188
|
+
} else {
|
|
189
|
+
// Bits Allocated (0028,0100) defines how much space is allocated
|
|
190
|
+
// in the buffer for every sample in bits.
|
|
191
|
+
let bitsAllocated = getTagValue(dataSet, "x00280100");
|
|
192
|
+
// Pixel Representation (0028,0103) is either unsigned (0) or signed (1).
|
|
193
|
+
// The default is unsigned.
|
|
194
|
+
let pixelRepresentation = getTagValue(dataSet, "x00280103");
|
|
195
|
+
let representation =
|
|
196
|
+
pixelRepresentation === 1
|
|
197
|
+
? "Sint" + bitsAllocated
|
|
198
|
+
: "Uint" + bitsAllocated;
|
|
199
|
+
return representation;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Get a typed array from a representation type
|
|
205
|
+
* @instance
|
|
206
|
+
* @function getTypedArrayFromDataType
|
|
207
|
+
* @param {Object} dataType - The data type
|
|
208
|
+
* @returns {TypedArray} The typed array
|
|
209
|
+
*/
|
|
210
|
+
export const getTypedArrayFromDataType = function (dataType) {
|
|
211
|
+
let repr = dataType.toLowerCase();
|
|
212
|
+
let typedArray = has(TYPES_TO_TYPEDARRAY, repr)
|
|
213
|
+
? TYPES_TO_TYPEDARRAY[repr]
|
|
214
|
+
: null;
|
|
215
|
+
if (!typedArray) {
|
|
216
|
+
console.error("invalida data type: ", dataType);
|
|
217
|
+
}
|
|
218
|
+
return typedArray;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Create and return a typed array from the pixel data
|
|
223
|
+
* @instance
|
|
224
|
+
* @function getPixelTypedArray
|
|
225
|
+
* @param {Object} dataSet - The cornerstone serie object
|
|
226
|
+
* @param {Object} pixelDataElement - The dataset metadata (dataSet.elements.x7fe00010)
|
|
227
|
+
* @returns {TypedArray} The pixel array as proper typed array
|
|
228
|
+
*/
|
|
229
|
+
export const getPixelTypedArray = function (dataSet, pixelDataElement) {
|
|
230
|
+
let buffer = dataSet.byteArray.buffer;
|
|
231
|
+
let offset = pixelDataElement.dataOffset;
|
|
232
|
+
let r = getPixelRepresentation(dataSet);
|
|
233
|
+
let typedArray = getTypedArrayFromDataType(r);
|
|
234
|
+
switch (typedArray) {
|
|
235
|
+
case Uint16Array:
|
|
236
|
+
length = pixelDataElement.length / 2;
|
|
237
|
+
break;
|
|
238
|
+
case Int16Array:
|
|
239
|
+
length = pixelDataElement.length / 2;
|
|
240
|
+
break;
|
|
241
|
+
case Uint32Array:
|
|
242
|
+
length = pixelDataElement.length / 4;
|
|
243
|
+
break;
|
|
244
|
+
case Int32Array:
|
|
245
|
+
length = pixelDataElement.length / 4;
|
|
246
|
+
break;
|
|
247
|
+
default:
|
|
248
|
+
length = pixelDataElement.length;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
return new typedArray(buffer, offset, length);
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Sort the array of images ids of a series trying with:
|
|
256
|
+
* - content time order, if the series has cardiacNumberOfImages tag > 1
|
|
257
|
+
* - position order, if series has needed patient position tags
|
|
258
|
+
* - instance order, if series has instance numbers tags
|
|
259
|
+
* The priority of the method depends on the instanceSortPriority value
|
|
260
|
+
* @instance
|
|
261
|
+
* @function getSortedStack
|
|
262
|
+
* @param {Object} seriesData - The dataset
|
|
263
|
+
* @param {Array} sortPriorities - TODO
|
|
264
|
+
* @param {Bool} returnSuccessMethod - TODO ask @SZ
|
|
265
|
+
* @return {Object} The sorted stack
|
|
266
|
+
*/
|
|
267
|
+
export const getSortedStack = function (
|
|
268
|
+
seriesData,
|
|
269
|
+
sortPriorities,
|
|
270
|
+
returnSuccessMethod
|
|
271
|
+
) {
|
|
272
|
+
let tryToSort = function (data, methods) {
|
|
273
|
+
if (isEmpty(methods)) {
|
|
274
|
+
if (returnSuccessMethod === true) {
|
|
275
|
+
return sorted;
|
|
276
|
+
} else {
|
|
277
|
+
return sorted;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
let sortMethod = methods.shift();
|
|
282
|
+
try {
|
|
283
|
+
var sorted = sortBy(data.imageIds, function (imageId) {
|
|
284
|
+
return sortStackCallback(data, imageId, sortMethod);
|
|
285
|
+
});
|
|
286
|
+
if (returnSuccessMethod === true) {
|
|
287
|
+
return sorted;
|
|
288
|
+
} else {
|
|
289
|
+
return sorted;
|
|
290
|
+
}
|
|
291
|
+
} catch (ex) {
|
|
292
|
+
return tryToSort(data, methods);
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
// sortPriorities will be shifted, so clone it before calling the tryToSort fucntion
|
|
297
|
+
let clonedList = clone(sortPriorities);
|
|
298
|
+
return tryToSort(seriesData, clonedList);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Sort the array of instanceUIDs according to imageIds sorted using sortSeriesStack
|
|
303
|
+
* @instance
|
|
304
|
+
* @function getSortedUIDs
|
|
305
|
+
* @param {Object} seriesData - The dataset
|
|
306
|
+
* @return {Object} The sorted instanceUIDs
|
|
307
|
+
*/
|
|
308
|
+
export const getSortedUIDs = function (seriesData) {
|
|
309
|
+
let instanceUIDs = {};
|
|
310
|
+
forEach(seriesData.imageIds, function (imageId) {
|
|
311
|
+
instanceUIDs[seriesData.instances[imageId].metadata.instanceUID] = imageId;
|
|
312
|
+
});
|
|
313
|
+
return instanceUIDs;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Generate a randomUUID in the form 'uy0x2qz9jk9co642cjfus'
|
|
318
|
+
* @instance
|
|
319
|
+
* @function randomId
|
|
320
|
+
* @return {String} - Random uid
|
|
321
|
+
*/
|
|
322
|
+
export const randomId = function () {
|
|
323
|
+
return rand() + rand();
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Get the mean value of a specified dicom tag in a serie
|
|
328
|
+
* @instance
|
|
329
|
+
* @function getMeanValue
|
|
330
|
+
* @param {Object} series - The cornerstone series object
|
|
331
|
+
* @param {Object} tag - The target tag key
|
|
332
|
+
* @param {Bool} isArray - True if tag value is an array
|
|
333
|
+
* @return {Number} - Tag mean value
|
|
334
|
+
*/
|
|
335
|
+
export const getMeanValue = function (series, tag, isArray) {
|
|
336
|
+
let meanValue = isArray ? [] : 0;
|
|
337
|
+
|
|
338
|
+
forEach(series.imageIds, function (imageId) {
|
|
339
|
+
const tagValue = series.instances[imageId].metadata[tag];
|
|
340
|
+
if (tagValue.length === 2) {
|
|
341
|
+
meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
|
|
342
|
+
meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
|
|
343
|
+
} else if (tagValue.length === 3) {
|
|
344
|
+
meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
|
|
345
|
+
meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
|
|
346
|
+
meanValue[2] = meanValue[2] ? meanValue[2] + tagValue[2] : tagValue[2];
|
|
347
|
+
} else if (tagValue.length === 6) {
|
|
348
|
+
meanValue[0] = meanValue[0] ? meanValue[0] + tagValue[0] : tagValue[0];
|
|
349
|
+
meanValue[1] = meanValue[1] ? meanValue[1] + tagValue[1] : tagValue[1];
|
|
350
|
+
meanValue[2] = meanValue[2] ? meanValue[2] + tagValue[2] : tagValue[2];
|
|
351
|
+
meanValue[3] = meanValue[3] ? meanValue[3] + tagValue[3] : tagValue[3];
|
|
352
|
+
meanValue[4] = meanValue[4] ? meanValue[4] + tagValue[4] : tagValue[4];
|
|
353
|
+
meanValue[5] = meanValue[5] ? meanValue[5] + tagValue[5] : tagValue[5];
|
|
354
|
+
} else {
|
|
355
|
+
meanValue += tagValue;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
if (isArray) {
|
|
360
|
+
for (let i = 0; i < meanValue.length; i++) {
|
|
361
|
+
meanValue[i] /= series.imageIds.length;
|
|
362
|
+
}
|
|
363
|
+
} else {
|
|
364
|
+
meanValue /= series.imageIds.length;
|
|
365
|
+
}
|
|
366
|
+
return meanValue;
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Compute resliced metadata from a cornerstone data structure
|
|
371
|
+
* @instance
|
|
372
|
+
* @function getReslicedMetadata
|
|
373
|
+
* @param {String} reslicedSeriesId - The id of the resliced serie
|
|
374
|
+
* @param {String} fromOrientation - Source orientation (eg axial, coronal or sagittal)
|
|
375
|
+
* @param {String} toOrientation - Target orientation (eg axial, coronal or sagittal)
|
|
376
|
+
* @param {Object} seriesData - The original series data
|
|
377
|
+
* @param {String} imageLoaderName - The registered loader name
|
|
378
|
+
* @return {Object} - Cornerstone series object, filled only with metadata
|
|
379
|
+
*/
|
|
380
|
+
export const getReslicedMetadata = function (
|
|
381
|
+
reslicedSeriesId,
|
|
382
|
+
fromOrientation,
|
|
383
|
+
toOrientation,
|
|
384
|
+
seriesData,
|
|
385
|
+
imageLoaderName
|
|
386
|
+
) {
|
|
387
|
+
// get reslice metadata and apply the reslice algorithm
|
|
388
|
+
let permuteTable = resliceTable[fromOrientation][toOrientation];
|
|
389
|
+
let permuteAbsTable = permuteTable.map(function (v) {
|
|
390
|
+
return Math.abs(v);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// orthogonal reslice algorithm
|
|
394
|
+
let reslicedImageIds = [];
|
|
395
|
+
let reslicedInstances = {};
|
|
396
|
+
|
|
397
|
+
let sampleMetadata = seriesData.instances[seriesData.imageIds[0]].metadata;
|
|
398
|
+
|
|
399
|
+
let fromSize = [
|
|
400
|
+
sampleMetadata.x00280011,
|
|
401
|
+
sampleMetadata.x00280010,
|
|
402
|
+
seriesData.imageIds.length
|
|
403
|
+
];
|
|
404
|
+
let toSize = permuteValues(permuteAbsTable, fromSize);
|
|
405
|
+
let fromSpacing = spacingArray(seriesData, sampleMetadata);
|
|
406
|
+
let toSpacing = permuteValues(permuteAbsTable, fromSpacing);
|
|
407
|
+
let reslicedIOP = getReslicedIOP(sampleMetadata.x00200037, permuteTable);
|
|
408
|
+
|
|
409
|
+
for (let f = 0; f < toSize[2]; f++) {
|
|
410
|
+
let reslicedImageId = getDicomImageId(imageLoaderName);
|
|
411
|
+
reslicedImageIds.push(reslicedImageId);
|
|
412
|
+
|
|
413
|
+
let instanceId = uuidv4();
|
|
414
|
+
let reslicedIPP = getReslicedIPP(
|
|
415
|
+
sampleMetadata.x00200032,
|
|
416
|
+
sampleMetadata.x00200037,
|
|
417
|
+
reslicedIOP,
|
|
418
|
+
permuteTable,
|
|
419
|
+
f,
|
|
420
|
+
fromSize,
|
|
421
|
+
toSize,
|
|
422
|
+
fromSpacing
|
|
423
|
+
);
|
|
424
|
+
let metadata = extend(clone(sampleMetadata), {
|
|
425
|
+
// pixel representation
|
|
426
|
+
x00280100: sampleMetadata.x00280100,
|
|
427
|
+
x00280103: sampleMetadata.x00280103,
|
|
428
|
+
// resliced series sizes
|
|
429
|
+
x00280010: toSize[1], // rows
|
|
430
|
+
x00280011: toSize[0], // cols
|
|
431
|
+
// resliced series spacing
|
|
432
|
+
x00280030: [toSpacing[1], toSpacing[0]],
|
|
433
|
+
x00180050: [toSpacing[2]],
|
|
434
|
+
// remove min and max pixelvalue from metadata before calling the createCustomImage function:
|
|
435
|
+
// need to recalculate the min and max pixel values on the new instance pixelData
|
|
436
|
+
x00280106: undefined,
|
|
437
|
+
x00280107: undefined,
|
|
438
|
+
// resliced series data
|
|
439
|
+
x0020000d: sampleMetadata.x0020000d,
|
|
440
|
+
x0020000e: reslicedSeriesId,
|
|
441
|
+
x00200011: random(10000),
|
|
442
|
+
x00080018: instanceId,
|
|
443
|
+
x00020003: instanceId,
|
|
444
|
+
x00200013: f + 1,
|
|
445
|
+
x00201041: getReslicedSliceLocation(reslicedIOP, reslicedIPP),
|
|
446
|
+
x00100010: sampleMetadata.x00100010,
|
|
447
|
+
x00081030: sampleMetadata.x00081030,
|
|
448
|
+
x00080020: sampleMetadata.x00080020,
|
|
449
|
+
x00080030: sampleMetadata.x00080030,
|
|
450
|
+
x00080061: sampleMetadata.x00080061,
|
|
451
|
+
x0008103e: sampleMetadata.x0008103e,
|
|
452
|
+
x00080021: sampleMetadata.x00080021,
|
|
453
|
+
x00080031: sampleMetadata.x00080031,
|
|
454
|
+
x00080060: sampleMetadata.x00080060,
|
|
455
|
+
x00280008: sampleMetadata.x00280008,
|
|
456
|
+
x00101010: sampleMetadata.x00101010,
|
|
457
|
+
x00020010: sampleMetadata.x00020010,
|
|
458
|
+
x00200052: sampleMetadata.x00200052,
|
|
459
|
+
// data needed to obtain a good rendering
|
|
460
|
+
x00281050: sampleMetadata.x00281050,
|
|
461
|
+
x00281051: sampleMetadata.x00281051,
|
|
462
|
+
x00281052: sampleMetadata.x00281052,
|
|
463
|
+
x00281053: sampleMetadata.x00281053,
|
|
464
|
+
// new image orientation
|
|
465
|
+
x00200037: reslicedIOP,
|
|
466
|
+
// new image position
|
|
467
|
+
x00200032: reslicedIPP,
|
|
468
|
+
x00280106: sampleMetadata.x00280106,
|
|
469
|
+
x00280107: sampleMetadata.x00280107
|
|
470
|
+
});
|
|
471
|
+
|
|
472
|
+
// set human readable metadata
|
|
473
|
+
metadata.seriesUID = reslicedSeriesId;
|
|
474
|
+
metadata.rows = metadata.x00280010;
|
|
475
|
+
metadata.cols = metadata.x00280011;
|
|
476
|
+
metadata.imageOrientation = metadata.x00200037;
|
|
477
|
+
metadata.imagePosition = metadata.x00200032;
|
|
478
|
+
metadata.pixelSpacing = metadata.x00280030;
|
|
479
|
+
metadata.instanceUID = metadata.x00080018;
|
|
480
|
+
metadata.minPixelValue = metadata.x00280106;
|
|
481
|
+
metadata.maxPixelValue = metadata.x00280107;
|
|
482
|
+
metadata.sliceThickness = toSpacing[2];
|
|
483
|
+
|
|
484
|
+
reslicedInstances[reslicedImageId] = {
|
|
485
|
+
instanceId: instanceId,
|
|
486
|
+
metadata: metadata,
|
|
487
|
+
permuteTable: permuteTable
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
imageIds: reslicedImageIds,
|
|
493
|
+
instances: reslicedInstances,
|
|
494
|
+
currentImageIdIndex: 0
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Compute cmpr metadata from pyCmpr data (generated using Scyther {@link https://github.com/dvisionlab/Scyther})
|
|
500
|
+
* @instance
|
|
501
|
+
* @function getCmprMetadata
|
|
502
|
+
* @param {String} reslicedSeriesId - The id of the resliced serie
|
|
503
|
+
* @param {String} imageLoaderName - The registered loader name
|
|
504
|
+
* @param {Object} header - The header of the resliced serie from Scyther
|
|
505
|
+
* @return {Object} - Cornerstone series object, filled only with metadata
|
|
506
|
+
*/
|
|
507
|
+
export const getCmprMetadata = function (
|
|
508
|
+
reslicedSeriesId,
|
|
509
|
+
imageLoaderName,
|
|
510
|
+
header
|
|
511
|
+
) {
|
|
512
|
+
let reslicedImageIds = [];
|
|
513
|
+
let reslicedInstances = {};
|
|
514
|
+
|
|
515
|
+
for (let f = 0; f < header.frames_number; f++) {
|
|
516
|
+
let reslicedImageId = getDicomImageId(imageLoaderName);
|
|
517
|
+
reslicedImageIds.push(reslicedImageId);
|
|
518
|
+
|
|
519
|
+
let instanceId = uuidv4();
|
|
520
|
+
|
|
521
|
+
let metadata = {
|
|
522
|
+
// pixel representation
|
|
523
|
+
x00280100: header.repr,
|
|
524
|
+
// Bits Allocated
|
|
525
|
+
x00280103: header.repr,
|
|
526
|
+
// resliced series sizes
|
|
527
|
+
x00280010: header.rows, // rows
|
|
528
|
+
x00280011: header.cols, // cols
|
|
529
|
+
// resliced series spacing
|
|
530
|
+
x00280030: [header.spacing[1], header.spacing[0]],
|
|
531
|
+
x00180050: [header.distance_btw_slices],
|
|
532
|
+
// remove min and max pixelvalue from metadata before calling the createCustomImage function:
|
|
533
|
+
// need to recalculate the min and max pixel values on the new instance pixelData
|
|
534
|
+
x00280106: undefined,
|
|
535
|
+
x00280107: undefined,
|
|
536
|
+
// resliced series data
|
|
537
|
+
// x0020000d: sampleMetadata.x0020000d, //Study Instance UID
|
|
538
|
+
x0020000e: reslicedSeriesId,
|
|
539
|
+
x00200011: random(10000),
|
|
540
|
+
x00080018: instanceId,
|
|
541
|
+
x00020003: instanceId,
|
|
542
|
+
x00200013: f + 1,
|
|
543
|
+
// x00201041: getReslicedSliceLocation(reslicedIOP, reslicedIPP), // Slice Location
|
|
544
|
+
// x00100010: sampleMetadata.x00100010,
|
|
545
|
+
// x00081030: sampleMetadata.x00081030,
|
|
546
|
+
// x00080020: sampleMetadata.x00080020,
|
|
547
|
+
// x00080030: sampleMetadata.x00080030,
|
|
548
|
+
// x00080061: sampleMetadata.x00080061,
|
|
549
|
+
// x0008103e: sampleMetadata.x0008103e,
|
|
550
|
+
// x00080021: sampleMetadata.x00080021,
|
|
551
|
+
// x00080031: sampleMetadata.x00080031,
|
|
552
|
+
// x00080060: sampleMetadata.x00080060,
|
|
553
|
+
// x00280008: sampleMetadata.x00280008,
|
|
554
|
+
// x00101010: sampleMetadata.x00101010,
|
|
555
|
+
// x00020010: sampleMetadata.x00020010,
|
|
556
|
+
// x00200052: sampleMetadata.x00200052,
|
|
557
|
+
// data needed to obtain a good rendering
|
|
558
|
+
x00281050: [header.wwwl[1] / 2], // [wl]
|
|
559
|
+
x00281051: [header.wwwl[0]], // [ww]
|
|
560
|
+
x00281052: [header.intercept],
|
|
561
|
+
x00281053: [header.slope],
|
|
562
|
+
// new image orientation (IOP)
|
|
563
|
+
x00200037: header.iop ? header.iop.slice(f * 6, (f + 1) * 6) : null,
|
|
564
|
+
// new image position (IPP)
|
|
565
|
+
x00200032: header.ipp ? header.ipp.slice(f * 3, (f + 1) * 3) : null
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
reslicedInstances[reslicedImageId] = {
|
|
569
|
+
instanceId: instanceId,
|
|
570
|
+
metadata: metadata
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return {
|
|
575
|
+
imageIds: reslicedImageIds,
|
|
576
|
+
instances: reslicedInstances
|
|
577
|
+
};
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Get pixel data for a single resliced slice, from cornerstone data structure
|
|
582
|
+
* @instance
|
|
583
|
+
* @function getReslicedPixeldata
|
|
584
|
+
* @param {String} imageId - The id of the resulting image
|
|
585
|
+
* @param {Object} originalData - The original series data (source)
|
|
586
|
+
* @param {Object} reslicedData - The resliced series data (target)
|
|
587
|
+
* @return {Object} - A single resliced slice pixel array
|
|
588
|
+
*/
|
|
589
|
+
export const getReslicedPixeldata = function (
|
|
590
|
+
imageId,
|
|
591
|
+
originalData,
|
|
592
|
+
reslicedData
|
|
593
|
+
) {
|
|
594
|
+
// resliced metadata must be already available
|
|
595
|
+
let reslicedInstance = reslicedData.instances[imageId];
|
|
596
|
+
let reslicedMetadata = reslicedInstance.metadata;
|
|
597
|
+
let permuteAbsTable = reslicedInstance.permuteTable.map(function (v) {
|
|
598
|
+
return Math.abs(v);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
// compute resliced series pixelData, use the correct typedarray
|
|
602
|
+
let rows = reslicedMetadata.x00280010;
|
|
603
|
+
let cols = reslicedMetadata.x00280011;
|
|
604
|
+
let reslicedSlice = getTypedArray(reslicedMetadata, rows * cols);
|
|
605
|
+
|
|
606
|
+
let frame = indexOf(reslicedData.imageIds, imageId);
|
|
607
|
+
let originalInstance = originalData.instances[originalData.imageIds[0]];
|
|
608
|
+
let fromCols = originalInstance.metadata.x00280011;
|
|
609
|
+
|
|
610
|
+
function getPixelValue(ijf) {
|
|
611
|
+
let i = ijf[0];
|
|
612
|
+
let j = ijf[1];
|
|
613
|
+
let f = ijf[2];
|
|
614
|
+
|
|
615
|
+
let cachedImage = find(cornerstone.imageCache.cachedImages, [
|
|
616
|
+
"imageId",
|
|
617
|
+
originalData.imageIds[f]
|
|
618
|
+
]);
|
|
619
|
+
let targetPixeldata = cachedImage.image.getPixelData();
|
|
620
|
+
let index = j * fromCols + i;
|
|
621
|
+
return targetPixeldata[index];
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// flip f values
|
|
625
|
+
if (isNegativeSign(reslicedInstance.permuteTable[2])) {
|
|
626
|
+
frame = reslicedData.imageIds.length - frame;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
for (let j = 0; j < rows; j++) {
|
|
630
|
+
for (let i = 0; i < cols; i++) {
|
|
631
|
+
let ijf = [0, 0, 0];
|
|
632
|
+
ijf[permuteAbsTable[0]] = i;
|
|
633
|
+
ijf[permuteAbsTable[1]] = j;
|
|
634
|
+
ijf[permuteAbsTable[2]] = frame;
|
|
635
|
+
|
|
636
|
+
// flip j index
|
|
637
|
+
let index;
|
|
638
|
+
if (isNegativeSign(reslicedInstance.permuteTable[1])) {
|
|
639
|
+
index = rows * cols - j * cols + i;
|
|
640
|
+
} else {
|
|
641
|
+
// let i_padded = Math.floor(i * originalSampleMetadata.x00180050 / originalSampleMetadata.x00280030[0]);
|
|
642
|
+
index = j * cols + i;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
reslicedSlice[index] = getPixelValue(ijf);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return reslicedSlice;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Get distance between two slices
|
|
653
|
+
* @instance
|
|
654
|
+
* @function getDistanceBetweenSlices
|
|
655
|
+
* @param {Object} seriesData - The series data
|
|
656
|
+
* @param {Number} sliceIndex1 - The first slice index
|
|
657
|
+
* @param {Number} sliceIndex2 - The second slice index
|
|
658
|
+
* @return {Number} - The distance value
|
|
659
|
+
*/
|
|
660
|
+
export const getDistanceBetweenSlices = function (
|
|
661
|
+
seriesData,
|
|
662
|
+
sliceIndex1,
|
|
663
|
+
sliceIndex2
|
|
664
|
+
) {
|
|
665
|
+
if (seriesData.imageIds.length <= 1) {
|
|
666
|
+
return 0;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
let imageId1 = seriesData.imageIds[sliceIndex1];
|
|
670
|
+
let instance1 = seriesData.instances[imageId1];
|
|
671
|
+
let metadata1 = instance1.metadata;
|
|
672
|
+
let imageOrientation = metadata1.imageOrientation
|
|
673
|
+
? metadata1.imageOrientation
|
|
674
|
+
: metadata1.x00200037;
|
|
675
|
+
let imagePosition = metadata1.imagePosition
|
|
676
|
+
? metadata1.imagePosition
|
|
677
|
+
: metadata1.x00200032;
|
|
678
|
+
|
|
679
|
+
if (imageOrientation && imagePosition) {
|
|
680
|
+
let normal = getNormalOrientation(imageOrientation);
|
|
681
|
+
let d1 =
|
|
682
|
+
normal[0] * imagePosition[0] +
|
|
683
|
+
normal[1] * imagePosition[1] +
|
|
684
|
+
normal[2] * imagePosition[2];
|
|
685
|
+
|
|
686
|
+
let imageId2 = seriesData.imageIds[sliceIndex2];
|
|
687
|
+
let instance2 = seriesData.instances[imageId2];
|
|
688
|
+
let metadata2 = instance2.metadata;
|
|
689
|
+
let imagePosition2 = metadata2.imagePosition
|
|
690
|
+
? metadata2.imagePosition
|
|
691
|
+
: metadata2.x00200032;
|
|
692
|
+
|
|
693
|
+
let d2 =
|
|
694
|
+
normal[0] * imagePosition2[0] +
|
|
695
|
+
normal[1] * imagePosition2[1] +
|
|
696
|
+
normal[2] * imagePosition2[2];
|
|
697
|
+
|
|
698
|
+
return Math.abs(d1 - d2);
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Parse a DICOM Tag according to its type
|
|
704
|
+
* @instance
|
|
705
|
+
* @function parseTag
|
|
706
|
+
* @param {Object} dataSet - The parsed dataset object from dicom parser
|
|
707
|
+
* @param {String} propertyName - The tag name
|
|
708
|
+
* @param {Object} element - The parsed dataset element
|
|
709
|
+
* @return {String} - The DICOM Tag value
|
|
710
|
+
*/
|
|
711
|
+
export const parseTag = function (dataSet, propertyName, element) {
|
|
712
|
+
// GET VR
|
|
713
|
+
var tagData = dataSet.elements[propertyName] || {};
|
|
714
|
+
var vr = tagData.vr;
|
|
715
|
+
if (!vr) {
|
|
716
|
+
// use dicom dict to get VR
|
|
717
|
+
var tag = getDICOMTag(propertyName);
|
|
718
|
+
if (tag && tag.vr) {
|
|
719
|
+
vr = tag.vr;
|
|
720
|
+
} else {
|
|
721
|
+
return element;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
var value;
|
|
726
|
+
|
|
727
|
+
if (isStringVr(vr)) {
|
|
728
|
+
// We ask the dataset to give us the element's data in string form.
|
|
729
|
+
// Most elements are strings but some aren't so we do a quick check
|
|
730
|
+
// to make sure it actually has all ascii characters so we know it is
|
|
731
|
+
// reasonable to display it.
|
|
732
|
+
var str = dataSet.string(propertyName);
|
|
733
|
+
if (str === undefined) {
|
|
734
|
+
return undefined;
|
|
735
|
+
} else {
|
|
736
|
+
// the string will be undefined if the element is present but has no data
|
|
737
|
+
// (i.e. attribute is of type 2 or 3) so we only display the string if it has
|
|
738
|
+
// data. Note that the length of the element will be 0 to indicate "no data"
|
|
739
|
+
// so we don't put anything here for the value in that case.
|
|
740
|
+
value = str;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// A string of characters representing an Integer in base-10 (decimal),
|
|
744
|
+
// shall contain only the characters 0 - 9, with an optional leading "+" or "-".
|
|
745
|
+
// It may be padded with leading and/or trailing spaces. Embedded spaces
|
|
746
|
+
// are not allowed. The integer, n, represented shall be in the range:
|
|
747
|
+
// -231 <= n <= (231 - 1).
|
|
748
|
+
if (vr === "IS") {
|
|
749
|
+
value = parseInt(value);
|
|
750
|
+
}
|
|
751
|
+
// A string of characters representing either a fixed point number
|
|
752
|
+
// or a floating point number. A fixed point number shall contain only
|
|
753
|
+
// the characters 0-9 with an optional leading "+" or "-" and an optional "."
|
|
754
|
+
// to mark the decimal point. A floating point number shall be conveyed
|
|
755
|
+
// as defined in ANSI X3.9, with an "E" or "e" to indicate the start
|
|
756
|
+
// of the exponent. Decimal Strings may be padded with leading or trailing spaces.
|
|
757
|
+
// Embedded spaces are not allowed.
|
|
758
|
+
else if (vr === "DS") {
|
|
759
|
+
value = value.split("\\").map(Number);
|
|
760
|
+
if (propertyName == "x00281050" || propertyName == "x00281051") {
|
|
761
|
+
value = value.length > 0 ? value[0] : value;
|
|
762
|
+
} else {
|
|
763
|
+
value = value.length == 1 ? value[0] : value;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
// A string of characters of the format YYYYMMDD; where YYYY shall contain year,
|
|
767
|
+
// MM shall contain the month, and DD shall contain the day,
|
|
768
|
+
// interpreted as a date of the Gregorian calendar system.
|
|
769
|
+
else if (vr === "DA") {
|
|
770
|
+
value = parseDateTag(value, false);
|
|
771
|
+
}
|
|
772
|
+
// A concatenated date-time character string in the format:
|
|
773
|
+
// YYYYMMDDHHMMSS.FFFFFF
|
|
774
|
+
else if (vr === "DT") {
|
|
775
|
+
value = parseDateTimeTag(value);
|
|
776
|
+
}
|
|
777
|
+
// A string of characters of the format HHMMSS.FFFFFF; where HH contains hours
|
|
778
|
+
// (range "00" - "23"), MM contains minutes (range "00" - "59"),
|
|
779
|
+
// SS contains seconds (range "00" - "60"), and FFFFFF contains a fractional
|
|
780
|
+
// part of a second as small as 1 millionth of a second (range "000000" - "999999").
|
|
781
|
+
else if (vr === "TM") {
|
|
782
|
+
value = parseTimeTag(value);
|
|
783
|
+
}
|
|
784
|
+
// Specific Character Set (0008,0005) identifies the Character Set that expands or
|
|
785
|
+
// replaces the Basic Graphic Set (ISO 646) for values of Data Elements that have
|
|
786
|
+
// Value Representation of SH, LO, ST, PN, LT, UC or UT.
|
|
787
|
+
// If the Attribute Specific Character Set (0008,0005) is not present or has only
|
|
788
|
+
// a single value, Code Extension techniques are not used. Defined Terms for the
|
|
789
|
+
// Attribute Specific Character Set (0008,0005), when single valued, are derived
|
|
790
|
+
// from the International Registration Number as per ISO 2375
|
|
791
|
+
// (e.g., ISO_IR 100 for Latin alphabet No. 1).
|
|
792
|
+
// See https://github.com/radialogica/dicom-character-set
|
|
793
|
+
else if (
|
|
794
|
+
vr == "PN" ||
|
|
795
|
+
vr == "SH" ||
|
|
796
|
+
vr == "LO" ||
|
|
797
|
+
vr == "ST" ||
|
|
798
|
+
vr == "LT" ||
|
|
799
|
+
vr == "UC" ||
|
|
800
|
+
vr == "UT"
|
|
801
|
+
) {
|
|
802
|
+
// get character set
|
|
803
|
+
let characterSet = dataSet.string("x00080005");
|
|
804
|
+
if (characterSet) {
|
|
805
|
+
let data = dataSet.elements[propertyName];
|
|
806
|
+
let arr = new Uint8Array(
|
|
807
|
+
dataSet.byteArray.buffer,
|
|
808
|
+
data.dataOffset,
|
|
809
|
+
data.length
|
|
810
|
+
);
|
|
811
|
+
value = convertBytes(characterSet, arr, {
|
|
812
|
+
vr: vr
|
|
813
|
+
});
|
|
814
|
+
arr = null;
|
|
815
|
+
}
|
|
816
|
+
if (vr == "PN") {
|
|
817
|
+
// PatientName tag value is: "LastName^FirstName^MiddleName".
|
|
818
|
+
// Spaces inside each name component are permitted. If you don't know
|
|
819
|
+
// any of the three components, just leave it empty.
|
|
820
|
+
// Actually you may even append a name prefix (^professor) and
|
|
821
|
+
// a name suffix (^senior) so you have a maximum of 5 components.
|
|
822
|
+
value = parsePatientNameTag(value);
|
|
823
|
+
}
|
|
824
|
+
value = value.replace(/\0/g, ""); // remove null char (\u0000)
|
|
825
|
+
}
|
|
826
|
+
// A string of characters with one of the following formats
|
|
827
|
+
// -- nnnD, nnnW, nnnM, nnnY; where nnn shall contain the number of days for D,
|
|
828
|
+
// weeks for W, months for M, or years for Y.
|
|
829
|
+
else if (vr == "AS") {
|
|
830
|
+
value = parseAgeTag(value);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// A string of characters with leading or trailing spaces (20H) being non-significant.
|
|
834
|
+
else if (vr === "CS") {
|
|
835
|
+
if (propertyName === "x00041500") {
|
|
836
|
+
value = parseDICOMFileIDTag(value);
|
|
837
|
+
} else {
|
|
838
|
+
value = value.split("\\").join(", ");
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
} else if (vr === "US") {
|
|
842
|
+
value = dataSet.uint16(propertyName);
|
|
843
|
+
} else if (vr === "SS") {
|
|
844
|
+
value = dataSet.int16(propertyName);
|
|
845
|
+
} else if (vr === "US|SS") {
|
|
846
|
+
value = dataSet.int16(propertyName);
|
|
847
|
+
} else if (vr === "UL") {
|
|
848
|
+
value = dataSet.uint32(propertyName);
|
|
849
|
+
} else if (vr === "SL") {
|
|
850
|
+
value = dataSet.int32(propertyName);
|
|
851
|
+
} else if (vr == "FD") {
|
|
852
|
+
value = dataSet.double(propertyName);
|
|
853
|
+
} else if (vr == "FL") {
|
|
854
|
+
value = dataSet.float(propertyName);
|
|
855
|
+
} else if (
|
|
856
|
+
vr === "OB" ||
|
|
857
|
+
vr === "OW" ||
|
|
858
|
+
vr === "OW|OB" ||
|
|
859
|
+
vr === "US|OW" ||
|
|
860
|
+
vr === "UN" ||
|
|
861
|
+
vr === "OF" ||
|
|
862
|
+
vr === "UT"
|
|
863
|
+
) {
|
|
864
|
+
// If it is some other length and we have no string
|
|
865
|
+
if (element.length === 2) {
|
|
866
|
+
value =
|
|
867
|
+
"binary data of length " +
|
|
868
|
+
element.length +
|
|
869
|
+
" as uint16: " +
|
|
870
|
+
dataSet.uint16(propertyName);
|
|
871
|
+
} else if (element.length === 4) {
|
|
872
|
+
value =
|
|
873
|
+
"binary data of length " +
|
|
874
|
+
element.length +
|
|
875
|
+
" as uint32: " +
|
|
876
|
+
dataSet.uint32(propertyName);
|
|
877
|
+
} else {
|
|
878
|
+
value = "binary data of length " + element.length + " and VR " + vr;
|
|
879
|
+
}
|
|
880
|
+
} else if (vr === "AT") {
|
|
881
|
+
var group = dataSet.uint16(propertyName, 0);
|
|
882
|
+
if (group) {
|
|
883
|
+
var groupHexStr = ("0000" + group.toString(16)).substr(-4);
|
|
884
|
+
var elm = dataSet.uint16(propertyName, 1);
|
|
885
|
+
var elmHexStr = ("0000" + elm.toString(16)).substr(-4);
|
|
886
|
+
value = "x" + groupHexStr + elmHexStr;
|
|
887
|
+
} else {
|
|
888
|
+
value = "";
|
|
889
|
+
}
|
|
890
|
+
} else if (vr === "SQ") {
|
|
891
|
+
// parse the nested tags
|
|
892
|
+
var subTags = map(element, function (obj) {
|
|
893
|
+
return map(obj, function (v, k) {
|
|
894
|
+
return parseTag(dataSet, k, v);
|
|
895
|
+
});
|
|
896
|
+
});
|
|
897
|
+
|
|
898
|
+
value = subTags;
|
|
899
|
+
} else {
|
|
900
|
+
// If it is some other length and we have no string
|
|
901
|
+
value = "no display code for VR " + vr;
|
|
902
|
+
}
|
|
903
|
+
return value;
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
/* Internal module functions */
|
|
907
|
+
|
|
908
|
+
/**
|
|
909
|
+
* Returns the sorting value of the image id in the array of image ids
|
|
910
|
+
* of the series according with the chosen sorting method
|
|
911
|
+
* @instance
|
|
912
|
+
* @function sortStackCallback
|
|
913
|
+
* @param {Object} seriesData - The original series data
|
|
914
|
+
* @param {String} imageId - The id of the target image
|
|
915
|
+
* @param {String} method - Orientation target
|
|
916
|
+
* @return {Number} - The sorting value (float)
|
|
917
|
+
*/
|
|
918
|
+
let sortStackCallback = function (seriesData, imageId, method) {
|
|
919
|
+
switch (method) {
|
|
920
|
+
case "instanceNumber":
|
|
921
|
+
var instanceNumber = seriesData.instances[imageId].metadata.x00200013;
|
|
922
|
+
instanceNumber = parseInt(instanceNumber);
|
|
923
|
+
return instanceNumber;
|
|
924
|
+
|
|
925
|
+
case "contentTime":
|
|
926
|
+
var cardiacNumberOfImages =
|
|
927
|
+
seriesData.instances[imageId].metadata.x00181090;
|
|
928
|
+
var contentTime = seriesData.instances[imageId].metadata.x00080033;
|
|
929
|
+
if (cardiacNumberOfImages && cardiacNumberOfImages > 1 && contentTime) {
|
|
930
|
+
return contentTime;
|
|
931
|
+
} else {
|
|
932
|
+
throw "Not a time series: cardiacNumberOfImages tag not available or <= 1.";
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
case "imagePosition":
|
|
936
|
+
var p = seriesData.instances[imageId].metadata.imagePosition;
|
|
937
|
+
|
|
938
|
+
p = map(p, function (value) {
|
|
939
|
+
return parseFloat(value);
|
|
940
|
+
});
|
|
941
|
+
|
|
942
|
+
var o = seriesData.instances[imageId].metadata.imageOrientation;
|
|
943
|
+
o = map(o, function (value) {
|
|
944
|
+
return parseFloat(value);
|
|
945
|
+
});
|
|
946
|
+
|
|
947
|
+
var v1, v2, v3;
|
|
948
|
+
v1 = o[0] * o[0] + o[3] * o[3];
|
|
949
|
+
v2 = o[1] * o[1] + o[4] * o[4];
|
|
950
|
+
v3 = o[2] * o[2] + o[5] * o[5];
|
|
951
|
+
|
|
952
|
+
var sortIndex;
|
|
953
|
+
if (v1 <= v2 && v2 <= v3) {
|
|
954
|
+
sortIndex = 0;
|
|
955
|
+
}
|
|
956
|
+
if (v2 <= v1 && v2 <= v3) {
|
|
957
|
+
sortIndex = 1;
|
|
958
|
+
}
|
|
959
|
+
if (v3 <= v1 && v3 <= v2) {
|
|
960
|
+
sortIndex = 2;
|
|
961
|
+
}
|
|
962
|
+
return p[sortIndex];
|
|
963
|
+
default:
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
};
|
|
967
|
+
|
|
968
|
+
/**
|
|
969
|
+
* Get the dicom tag code from dicom image
|
|
970
|
+
* @instance
|
|
971
|
+
* @function getDICOMTagCode
|
|
972
|
+
* @param {String} dicomTag - The original DICOM tag code
|
|
973
|
+
* @return {String} - The human readable DICOM tag code
|
|
974
|
+
*/
|
|
975
|
+
let getDICOMTagCode = function (code) {
|
|
976
|
+
let re = /x(\w{4})(\w{4})/;
|
|
977
|
+
let result = re.exec(code);
|
|
978
|
+
if (!result) {
|
|
979
|
+
return code;
|
|
980
|
+
}
|
|
981
|
+
let newCode = "(" + result[1] + "," + result[2] + ")";
|
|
982
|
+
newCode = newCode.toUpperCase();
|
|
983
|
+
return newCode;
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* Get the dicom tag from dicom tag code
|
|
988
|
+
* @instance
|
|
989
|
+
* @function getDICOMTag
|
|
990
|
+
* @param {String} dicomTagCode - The original DICOM tag code
|
|
991
|
+
* @return {String} - The human readable DICOM tag
|
|
992
|
+
*/
|
|
993
|
+
let getDICOMTag = function (code) {
|
|
994
|
+
let newCode = getDICOMTagCode(code);
|
|
995
|
+
let tag = TAG_DICT[newCode];
|
|
996
|
+
return tag;
|
|
997
|
+
};
|
|
998
|
+
|
|
999
|
+
/**
|
|
1000
|
+
* Convert date from dicom tag
|
|
1001
|
+
* @instance
|
|
1002
|
+
* @function formatDate
|
|
1003
|
+
* @param {Date} dicomDate - A date from a DICOM tag
|
|
1004
|
+
* @return {String} - The human readable date
|
|
1005
|
+
*/
|
|
1006
|
+
let formatDate = function (date) {
|
|
1007
|
+
let yyyy = date.slice(0, 4);
|
|
1008
|
+
let mm = date.slice(4, 6);
|
|
1009
|
+
let dd = date.slice(6, 8);
|
|
1010
|
+
return (
|
|
1011
|
+
yyyy + "-" + (mm[1] ? mm : "0" + mm[0]) + "-" + (dd[1] ? dd : "0" + dd[0])
|
|
1012
|
+
);
|
|
1013
|
+
};
|
|
1014
|
+
|
|
1015
|
+
/**
|
|
1016
|
+
* Convert datetime from dicom tag
|
|
1017
|
+
* @instance
|
|
1018
|
+
* @function formatDateTime
|
|
1019
|
+
* @param {Date} dicomDateTime - A dateTime from a DICOM tag
|
|
1020
|
+
* @return {String} - The human readable dateTime
|
|
1021
|
+
*/
|
|
1022
|
+
let formatDateTime = function (date) {
|
|
1023
|
+
let yyyy = date.slice(0, 4);
|
|
1024
|
+
let mm = date.slice(4, 6);
|
|
1025
|
+
let dd = date.slice(6, 8);
|
|
1026
|
+
let hh = date.slice(8, 10);
|
|
1027
|
+
let m = date.slice(10, 12);
|
|
1028
|
+
let ss = date.slice(12, 14);
|
|
1029
|
+
|
|
1030
|
+
return (
|
|
1031
|
+
yyyy +
|
|
1032
|
+
"-" +
|
|
1033
|
+
(mm[1] ? mm : "0" + mm[0]) +
|
|
1034
|
+
"-" +
|
|
1035
|
+
(dd[1] ? dd : "0" + dd[0]) +
|
|
1036
|
+
"/" +
|
|
1037
|
+
hh +
|
|
1038
|
+
":" +
|
|
1039
|
+
m +
|
|
1040
|
+
":" +
|
|
1041
|
+
ss
|
|
1042
|
+
);
|
|
1043
|
+
};
|
|
1044
|
+
|
|
1045
|
+
/**
|
|
1046
|
+
* Generate a random number and convert it to base 36 (0-9a-z)
|
|
1047
|
+
* @instance
|
|
1048
|
+
* @function rand
|
|
1049
|
+
* @return {Number} - base36 random number
|
|
1050
|
+
*/
|
|
1051
|
+
let rand = function () {
|
|
1052
|
+
return Math.random().toString(36).substr(2);
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Permute array values using orientation array
|
|
1057
|
+
* @instance
|
|
1058
|
+
* @function permuteValues
|
|
1059
|
+
* @param {Array} convertArray - The orientation array
|
|
1060
|
+
* @param {Array} sourceArray - The source array
|
|
1061
|
+
* @return {Array} - The converted array
|
|
1062
|
+
*/
|
|
1063
|
+
let permuteValues = function (convertArray, sourceArray) {
|
|
1064
|
+
let outputArray = new Array(convertArray.length);
|
|
1065
|
+
for (let i = 0; i < convertArray.length; i++) {
|
|
1066
|
+
outputArray[i] = sourceArray[convertArray[i]];
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
return outputArray;
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
/**
|
|
1073
|
+
* Check negative sign, considering also 0+ and 0-
|
|
1074
|
+
* @instance
|
|
1075
|
+
* @function isNegativeSign
|
|
1076
|
+
* @param {Number} x - The number to check
|
|
1077
|
+
* @return {Boolean} - Is negative boolean response
|
|
1078
|
+
*/
|
|
1079
|
+
let isNegativeSign = function (x) {
|
|
1080
|
+
return 1 / x !== 1 / Math.abs(x);
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Get typed array from tag and size of original array
|
|
1085
|
+
* @instance
|
|
1086
|
+
* @function getTypedArray
|
|
1087
|
+
* @param {String} tag - The DICOM tag used for pixel representation
|
|
1088
|
+
* @param {Number} size - The size of the array
|
|
1089
|
+
* @return {Array} - The typed array
|
|
1090
|
+
*/
|
|
1091
|
+
let getTypedArray = function (tags, size) {
|
|
1092
|
+
let r = getPixelRepresentation(tags);
|
|
1093
|
+
let typedArray = getTypedArrayFromDataType(r);
|
|
1094
|
+
return new typedArray(size);
|
|
1095
|
+
};
|
|
1096
|
+
|
|
1097
|
+
/**
|
|
1098
|
+
* Get resliced image orientation tag from permuteTable
|
|
1099
|
+
* @instance
|
|
1100
|
+
* @function getReslicedIOP
|
|
1101
|
+
* @param {Array} iop - The image orientation array
|
|
1102
|
+
* @param {Array} permuteTable - The matrix transformation
|
|
1103
|
+
* @return {Array} - The resliced image orientation array
|
|
1104
|
+
*/
|
|
1105
|
+
let getReslicedIOP = function (iop, permuteTable) {
|
|
1106
|
+
if (!iop) {
|
|
1107
|
+
return null;
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
// compute resliced iop
|
|
1111
|
+
let u = iop.slice(0, 3);
|
|
1112
|
+
let v = iop.slice(3, 6);
|
|
1113
|
+
|
|
1114
|
+
// abs the w array, the sign will be eventually changed during the permutation
|
|
1115
|
+
let w = getNormalOrientation(iop);
|
|
1116
|
+
// let absW = _.map(w, function(v) { return Math.abs(v); });
|
|
1117
|
+
|
|
1118
|
+
// resliced iop components
|
|
1119
|
+
let shuffledIop = permuteSignedArrays(permuteTable, [u, v, w]);
|
|
1120
|
+
|
|
1121
|
+
// keep the firts two components of shuffledIop
|
|
1122
|
+
return shuffledIop[0].concat(shuffledIop[1]);
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* Get resliced image position tag from permuteTable
|
|
1127
|
+
* @instance
|
|
1128
|
+
* @function getReslicedIPP
|
|
1129
|
+
* @param {Array} iop - The image position array
|
|
1130
|
+
* @param {Array} iop - The image orientation array
|
|
1131
|
+
* @param {Array} reslicedIOP - The resliced image orientation array
|
|
1132
|
+
* @param {Array} permuteTable - The matrix transformation
|
|
1133
|
+
* @param {Number} imageIndex - The index of the image
|
|
1134
|
+
* @param {Array} fromSize - The array of source image dimension
|
|
1135
|
+
* @param {Array} toSize - The array of target image dimension
|
|
1136
|
+
* @param {Array} fromSpacing - The spacing array
|
|
1137
|
+
* @return {Array} - The resliced image position array
|
|
1138
|
+
*/
|
|
1139
|
+
let getReslicedIPP = function (
|
|
1140
|
+
ipp,
|
|
1141
|
+
iop,
|
|
1142
|
+
reslicedIOP,
|
|
1143
|
+
permuteTable,
|
|
1144
|
+
imageIndex,
|
|
1145
|
+
fromSize,
|
|
1146
|
+
toSize,
|
|
1147
|
+
fromSpacing
|
|
1148
|
+
) {
|
|
1149
|
+
// compute resliced ipp
|
|
1150
|
+
let reslicedIPP = [];
|
|
1151
|
+
|
|
1152
|
+
// iop data
|
|
1153
|
+
let u = iop.slice(0, 3);
|
|
1154
|
+
let v = iop.slice(3, 6);
|
|
1155
|
+
let w = getNormalOrientation(iop);
|
|
1156
|
+
let absW = map(w, function (v) {
|
|
1157
|
+
return Math.abs(v);
|
|
1158
|
+
});
|
|
1159
|
+
let majorOriginalIndex = indexOf(absW, max(absW));
|
|
1160
|
+
|
|
1161
|
+
let normalReslicedIop = getNormalOrientation(reslicedIOP);
|
|
1162
|
+
normalReslicedIop = map(normalReslicedIop, function (v) {
|
|
1163
|
+
return Math.abs(v);
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
let majorIndex = indexOf(normalReslicedIop, max(normalReslicedIop));
|
|
1167
|
+
let index = isNegativeSign(permuteTable[majorIndex])
|
|
1168
|
+
? toSize[majorIndex] - imageIndex
|
|
1169
|
+
: imageIndex;
|
|
1170
|
+
|
|
1171
|
+
// flip z value on original slice
|
|
1172
|
+
if (isNegativeSign(permuteTable[1])) {
|
|
1173
|
+
ipp = ipp.map(function (val, i) {
|
|
1174
|
+
return val + fromSize[2] * fromSpacing[2] * w[i];
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
let spacing, versor;
|
|
1179
|
+
// to sagittal
|
|
1180
|
+
if (majorIndex == 0) {
|
|
1181
|
+
// original x spacing
|
|
1182
|
+
spacing = fromSpacing[0];
|
|
1183
|
+
versor = u;
|
|
1184
|
+
}
|
|
1185
|
+
// to coronal
|
|
1186
|
+
else if (majorIndex == 1) {
|
|
1187
|
+
// from sagittal
|
|
1188
|
+
if (majorOriginalIndex == 0) {
|
|
1189
|
+
spacing = fromSpacing[0];
|
|
1190
|
+
versor = u;
|
|
1191
|
+
|
|
1192
|
+
// overwrite index with the majorOriginalIndex position
|
|
1193
|
+
// index = isNegativeSign(permuteTable[majorOriginalIndex]) ? (toSize[majorOriginalIndex] - imageIndex) : imageIndex;
|
|
1194
|
+
}
|
|
1195
|
+
// from axial
|
|
1196
|
+
else if (majorOriginalIndex == 2) {
|
|
1197
|
+
spacing = fromSpacing[1];
|
|
1198
|
+
versor = v;
|
|
1199
|
+
|
|
1200
|
+
// overwrite index with the majorOriginalIndex position
|
|
1201
|
+
index = isNegativeSign(permuteTable[majorOriginalIndex])
|
|
1202
|
+
? toSize[majorOriginalIndex] - imageIndex
|
|
1203
|
+
: imageIndex;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
// to axial
|
|
1207
|
+
else if (majorIndex == 2) {
|
|
1208
|
+
// original y spacing
|
|
1209
|
+
spacing = fromSpacing[1];
|
|
1210
|
+
versor = v;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
reslicedIPP = ipp.map(function (val, i) {
|
|
1214
|
+
return val + index * spacing * versor[i];
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
return reslicedIPP;
|
|
1218
|
+
};
|
|
1219
|
+
|
|
1220
|
+
/**
|
|
1221
|
+
* Get resliced normal orientation vector
|
|
1222
|
+
* @instance
|
|
1223
|
+
* @function getReslicedSliceLocation
|
|
1224
|
+
* @param {Array} reslicedIOP - The resliced image orientation array
|
|
1225
|
+
* @param {Array} reslicedIPP - The resliced image position array
|
|
1226
|
+
* @return {Array} - The slice location as normal orientation vector
|
|
1227
|
+
*/
|
|
1228
|
+
let getReslicedSliceLocation = function (reslicedIOP, reslicedIPP) {
|
|
1229
|
+
let normalReslicedIop = getNormalOrientation(reslicedIOP);
|
|
1230
|
+
normalReslicedIop = map(normalReslicedIop, function (v) {
|
|
1231
|
+
return Math.abs(v);
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
let majorIndex = indexOf(normalReslicedIop, max(normalReslicedIop));
|
|
1235
|
+
return reslicedIPP[majorIndex];
|
|
1236
|
+
};
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* Get spacing array from seriesData
|
|
1240
|
+
* @instance
|
|
1241
|
+
* @function spacingArray
|
|
1242
|
+
* @param {Object} seriesData - The original series data
|
|
1243
|
+
* @param {Object} sampleMetadata - The medatata object
|
|
1244
|
+
* @return {Array} - The spacing array
|
|
1245
|
+
*/
|
|
1246
|
+
let spacingArray = function (seriesData, sampleMetadata) {
|
|
1247
|
+
// the spacingArray is as follows:
|
|
1248
|
+
// [0]: column pixelSpacing value (x00280030[1])
|
|
1249
|
+
// [1]: row pixelSpacing value (x00280030[0])
|
|
1250
|
+
// [2]: distance between slices, given the series imageOrientationPatient and
|
|
1251
|
+
// imagePositionPatient of the first two slices
|
|
1252
|
+
|
|
1253
|
+
let distanceBetweenSlices = sampleMetadata.x00180050
|
|
1254
|
+
? sampleMetadata.x00180050
|
|
1255
|
+
: getDistanceBetweenSlices(seriesData, 0, 1);
|
|
1256
|
+
|
|
1257
|
+
return [
|
|
1258
|
+
sampleMetadata.x00280030[1],
|
|
1259
|
+
sampleMetadata.x00280030[0],
|
|
1260
|
+
distanceBetweenSlices
|
|
1261
|
+
];
|
|
1262
|
+
};
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Permute an array
|
|
1266
|
+
* @instance
|
|
1267
|
+
* @function permuteSignedArrays
|
|
1268
|
+
* @param {Array} convertArray - The array used to convert source array
|
|
1269
|
+
* @param {Array} sourceArray - The source array
|
|
1270
|
+
* @return {Array} - The permuted array array
|
|
1271
|
+
*/
|
|
1272
|
+
let permuteSignedArrays = function (convertArray, sourceArray) {
|
|
1273
|
+
let outputArray = new Array(convertArray.length);
|
|
1274
|
+
for (let i = 0; i < convertArray.length; i++) {
|
|
1275
|
+
let sourceIndex = Math.abs(convertArray[i]);
|
|
1276
|
+
if (isNegativeSign(convertArray[i])) {
|
|
1277
|
+
outputArray[i] = sourceArray[sourceIndex].map(function (v) {
|
|
1278
|
+
return -v;
|
|
1279
|
+
});
|
|
1280
|
+
} else {
|
|
1281
|
+
outputArray[i] = sourceArray[sourceIndex];
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
return outputArray;
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Check if argument is a valid Date Object
|
|
1290
|
+
* @instance
|
|
1291
|
+
* @function isValidDate
|
|
1292
|
+
* @param {Date} d - The date object to be checked
|
|
1293
|
+
* @return {Boolean} - Boolean result
|
|
1294
|
+
*/
|
|
1295
|
+
const isValidDate = function (d) {
|
|
1296
|
+
return d instanceof Date && !isNaN(d);
|
|
1297
|
+
};
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Check if argument is a string of concatenated vrs
|
|
1301
|
+
* @instance
|
|
1302
|
+
* @function isStringVr
|
|
1303
|
+
* @param {String} vr - The string to be checked
|
|
1304
|
+
* @return {Boolean} - Boolean result
|
|
1305
|
+
*/
|
|
1306
|
+
const isStringVr = function (vr) {
|
|
1307
|
+
// vr can be a string of concatenated vrs
|
|
1308
|
+
vr = vr || "";
|
|
1309
|
+
vr = vr.split("|")[0];
|
|
1310
|
+
|
|
1311
|
+
if (
|
|
1312
|
+
vr === "AT" ||
|
|
1313
|
+
vr === "FL" ||
|
|
1314
|
+
vr === "FD" ||
|
|
1315
|
+
vr === "OB" ||
|
|
1316
|
+
vr === "OF" ||
|
|
1317
|
+
vr === "OW" ||
|
|
1318
|
+
vr === "SI" ||
|
|
1319
|
+
vr === "SQ" ||
|
|
1320
|
+
vr === "SS" ||
|
|
1321
|
+
vr === "UL" ||
|
|
1322
|
+
vr === "US"
|
|
1323
|
+
) {
|
|
1324
|
+
return false;
|
|
1325
|
+
}
|
|
1326
|
+
return true;
|
|
1327
|
+
};
|
|
1328
|
+
|
|
1329
|
+
/**
|
|
1330
|
+
* Parse a dicom date tag into human readable format
|
|
1331
|
+
* @instance
|
|
1332
|
+
* @function parseDateTag
|
|
1333
|
+
* @param {String} tagValue - The string to be parsed
|
|
1334
|
+
* @return {String} - The parsed result
|
|
1335
|
+
*/
|
|
1336
|
+
const parseDateTag = function (tagValue) {
|
|
1337
|
+
if (!tagValue) return;
|
|
1338
|
+
let year = tagValue.substring(0, 4);
|
|
1339
|
+
let month = tagValue.substring(4, 6);
|
|
1340
|
+
let day = tagValue.substring(6, 8);
|
|
1341
|
+
let date = new Date(year, month - 1, day);
|
|
1342
|
+
if (isValidDate(date) === true) {
|
|
1343
|
+
return date.toISOString();
|
|
1344
|
+
} else {
|
|
1345
|
+
return tagValue;
|
|
1346
|
+
}
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* Parse a dicom datetime tag into human readable format
|
|
1351
|
+
* @instance
|
|
1352
|
+
* @function parseDateTimeTag
|
|
1353
|
+
* @param {String} tagValue - The string to be parsed
|
|
1354
|
+
* @return {String} - The parsed result
|
|
1355
|
+
*/
|
|
1356
|
+
const parseDateTimeTag = function (tagValue) {
|
|
1357
|
+
if (!tagValue) return;
|
|
1358
|
+
let year = tagValue.substring(0, 4);
|
|
1359
|
+
let month = tagValue.substring(4, 6);
|
|
1360
|
+
let day = tagValue.substring(6, 8);
|
|
1361
|
+
let hour = tagValue.substring(8, 10);
|
|
1362
|
+
let min = tagValue.substring(10, 12);
|
|
1363
|
+
let sec = tagValue.substring(12, 14);
|
|
1364
|
+
let msec = tagValue.substring(15, 21);
|
|
1365
|
+
let date = new Date(year, month - 1, day, hour, min, sec, msec);
|
|
1366
|
+
if (isValidDate(date) === true) {
|
|
1367
|
+
return date.toISOString();
|
|
1368
|
+
} else {
|
|
1369
|
+
return tagValue;
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
|
|
1373
|
+
/**
|
|
1374
|
+
* Parse a dicom time tag into human readable format
|
|
1375
|
+
* @instance
|
|
1376
|
+
* @function parseTimeTag
|
|
1377
|
+
* @param {String} tagValue - The string to be parsed
|
|
1378
|
+
* @return {String} - The parsed result
|
|
1379
|
+
*/
|
|
1380
|
+
const parseTimeTag = function (tagValue) {
|
|
1381
|
+
if (!tagValue) return;
|
|
1382
|
+
let hour = tagValue.substring(0, 2);
|
|
1383
|
+
let min = tagValue.substring(2, 4);
|
|
1384
|
+
let sec = tagValue.substring(4, 6);
|
|
1385
|
+
let msec = tagValue.substring(7, 13) ? tagValue.substring(7, 13) : "0";
|
|
1386
|
+
let result = hour + ":" + min + ":" + sec + "." + msec;
|
|
1387
|
+
return result;
|
|
1388
|
+
};
|
|
1389
|
+
|
|
1390
|
+
/**
|
|
1391
|
+
* Parse a dicom patient tag into human readable format
|
|
1392
|
+
* @instance
|
|
1393
|
+
* @function parsePatientNameTag
|
|
1394
|
+
* @param {String} tagValue - The string to be parsed
|
|
1395
|
+
* @return {String} - The parsed result
|
|
1396
|
+
*/
|
|
1397
|
+
const parsePatientNameTag = function (tagValue) {
|
|
1398
|
+
if (!tagValue) return;
|
|
1399
|
+
return tagValue.replace(/\^/gi, " ");
|
|
1400
|
+
};
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* Parse a dicom age tag into human readable format
|
|
1404
|
+
* @instance
|
|
1405
|
+
* @function parseAgeTag
|
|
1406
|
+
* @param {String} tagValue - The string to be parsed
|
|
1407
|
+
* @return {String} - The parsed result
|
|
1408
|
+
*/
|
|
1409
|
+
const parseAgeTag = function (tagValue) {
|
|
1410
|
+
if (!tagValue) return;
|
|
1411
|
+
let regs = /(\d{3})(D|W|M|Y)/gim.exec(tagValue);
|
|
1412
|
+
if (regs) {
|
|
1413
|
+
return parseInt(regs[1]) + " " + regs[2];
|
|
1414
|
+
}
|
|
1415
|
+
};
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* Parse a dicom fileID tag into human readable format
|
|
1419
|
+
* @instance
|
|
1420
|
+
* @function parseDICOMFileIDTag
|
|
1421
|
+
* @param {String} tagValue - The string to be parsed
|
|
1422
|
+
* @return {String} - The parsed result
|
|
1423
|
+
*/
|
|
1424
|
+
const parseDICOMFileIDTag = function (tagValue) {
|
|
1425
|
+
// The DICOM File Service does not specify any "separator" between
|
|
1426
|
+
// the Components of the File ID. This is a Value Representation issue that
|
|
1427
|
+
// may be addressed in a specific manner by each Media Format Layer.
|
|
1428
|
+
// In DICOM IODs, File ID Components are generally handled as multiple
|
|
1429
|
+
// Values and separated by "backslashes".
|
|
1430
|
+
// There is no requirement that Media Format Layers use this separator.
|
|
1431
|
+
if (!tagValue) return;
|
|
1432
|
+
return tagValue.split("\\").join(path.sep);
|
|
1433
|
+
};
|
|
1434
|
+
|
|
1435
|
+
/**
|
|
1436
|
+
* Extract tag value according to its value rapresentation, see
|
|
1437
|
+
* {@link http://dicom.nema.org/dicom/2013/output/chtml/part05/sect_6.2.html}
|
|
1438
|
+
* @instance
|
|
1439
|
+
* @function getTagValue
|
|
1440
|
+
* @param {Object} dataSet - the dataset
|
|
1441
|
+
* @param {String} tag - the desired tag key
|
|
1442
|
+
* @return {Number | Array | String} - the desired tag value
|
|
1443
|
+
*/
|
|
1444
|
+
const getTagValue = function (dataSet, tag) {
|
|
1445
|
+
// tag value rapresentation
|
|
1446
|
+
if (!getDICOMTag(tag)) {
|
|
1447
|
+
return null;
|
|
1448
|
+
}
|
|
1449
|
+
let vr = getDICOMTag(tag).vr;
|
|
1450
|
+
|
|
1451
|
+
// parse value according to vr map
|
|
1452
|
+
let vrParsingMap = {
|
|
1453
|
+
// Date
|
|
1454
|
+
// string of characters of the format YYYYMMDD; where YYYY shall contain year,
|
|
1455
|
+
// MM shall contain the month, and DD shall contain the day,
|
|
1456
|
+
// interpreted as a date of the Gregorian calendar system.
|
|
1457
|
+
DA: function () {
|
|
1458
|
+
let dateString = dataSet.string(tag);
|
|
1459
|
+
return dateString ? formatDate(dateString) : "";
|
|
1460
|
+
},
|
|
1461
|
+
// Decimal String
|
|
1462
|
+
// A string of characters representing either a fixed point number
|
|
1463
|
+
// or a floating point number.
|
|
1464
|
+
DS: function () {
|
|
1465
|
+
let array = dataSet.string(tag)
|
|
1466
|
+
? dataSet.string(tag).split("\\").map(Number)
|
|
1467
|
+
: null;
|
|
1468
|
+
if (!array) {
|
|
1469
|
+
return null;
|
|
1470
|
+
}
|
|
1471
|
+
return array.length === 1 ? array[0] : array;
|
|
1472
|
+
},
|
|
1473
|
+
// Date Time
|
|
1474
|
+
// A concatenated date-time character string in the format:
|
|
1475
|
+
// YYYYMMDDHHMMSS.FFFFFF&ZZXX
|
|
1476
|
+
DT: function () {
|
|
1477
|
+
let dateString = dataSet.string(tag);
|
|
1478
|
+
return formatDateTime(dateString);
|
|
1479
|
+
},
|
|
1480
|
+
// Person Name
|
|
1481
|
+
// A character string encoded using a 5 component convention.
|
|
1482
|
+
// The character code 5CH (the BACKSLASH "\" in ISO-IR 6) shall
|
|
1483
|
+
// not be present, as it is used as the delimiter between values
|
|
1484
|
+
// in multiple valued data elements. The string may be padded
|
|
1485
|
+
// with trailing spaces. For human use, the five components
|
|
1486
|
+
// in their order of occurrence are: family name complex,
|
|
1487
|
+
// given name complex, middle name, name prefix, name suffix.
|
|
1488
|
+
PN: function () {
|
|
1489
|
+
let pn = dataSet.string(tag) ? dataSet.string(tag).split("^") : null;
|
|
1490
|
+
if (!pn) {
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
let pns = [pn[3], pn[0], pn[1], pn[2], pn[4]];
|
|
1495
|
+
return pns.join(" ").trim();
|
|
1496
|
+
},
|
|
1497
|
+
// Signed Short
|
|
1498
|
+
// Signed binary integer 16 bits long in 2's complement form
|
|
1499
|
+
SS: function () {
|
|
1500
|
+
return dataSet.uint16(tag);
|
|
1501
|
+
},
|
|
1502
|
+
// Unique Identifier
|
|
1503
|
+
// A character string containing a UID that is used to uniquely
|
|
1504
|
+
// identify a wide letiety of items. The UID is a series of numeric
|
|
1505
|
+
// components separated by the period "." character.
|
|
1506
|
+
UI: function () {
|
|
1507
|
+
return dataSet.string(tag);
|
|
1508
|
+
},
|
|
1509
|
+
// Unsigned Short
|
|
1510
|
+
// Unsigned binary integer 16 bits long.
|
|
1511
|
+
US: function () {
|
|
1512
|
+
return dataSet.uint16(tag);
|
|
1513
|
+
},
|
|
1514
|
+
"US|SS": function () {
|
|
1515
|
+
return dataSet.uint16(tag);
|
|
1516
|
+
}
|
|
1517
|
+
};
|
|
1518
|
+
return vrParsingMap[vr] ? vrParsingMap[vr]() : dataSet.string(tag);
|
|
1519
|
+
};
|
|
1520
|
+
|
|
1521
|
+
/**
|
|
1522
|
+
* Object used to convert data type to typed array
|
|
1523
|
+
* @object
|
|
1524
|
+
*/
|
|
1525
|
+
const TYPES_TO_TYPEDARRAY = {
|
|
1526
|
+
"unsigned char": Uint8Array,
|
|
1527
|
+
uchar: Uint8Array,
|
|
1528
|
+
uint8: Uint8Array,
|
|
1529
|
+
uint8_t: Uint8Array,
|
|
1530
|
+
|
|
1531
|
+
sint8: Int8Array,
|
|
1532
|
+
"signed char": Int8Array,
|
|
1533
|
+
int8: Int8Array,
|
|
1534
|
+
int8_t: Int8Array,
|
|
1535
|
+
|
|
1536
|
+
ushort: Uint16Array,
|
|
1537
|
+
"unsigned short": Uint16Array,
|
|
1538
|
+
"unsigned short int": Uint16Array,
|
|
1539
|
+
uint16: Uint16Array,
|
|
1540
|
+
uint16_t: Uint16Array,
|
|
1541
|
+
|
|
1542
|
+
sint16: Int16Array,
|
|
1543
|
+
short: Int16Array,
|
|
1544
|
+
"short int": Int16Array,
|
|
1545
|
+
"signed short": Int16Array,
|
|
1546
|
+
"signed short int": Int16Array,
|
|
1547
|
+
int16: Int16Array,
|
|
1548
|
+
int16_t: Int16Array,
|
|
1549
|
+
|
|
1550
|
+
sint32: Int32Array,
|
|
1551
|
+
int: Int32Array,
|
|
1552
|
+
"signed int": Int32Array,
|
|
1553
|
+
int32: Int32Array,
|
|
1554
|
+
int32_t: Int32Array,
|
|
1555
|
+
|
|
1556
|
+
uint: Uint32Array,
|
|
1557
|
+
"unsigned int": Uint32Array,
|
|
1558
|
+
uint32: Uint32Array,
|
|
1559
|
+
uint32_t: Uint32Array,
|
|
1560
|
+
|
|
1561
|
+
float: Float32Array,
|
|
1562
|
+
double: Float64Array
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1565
|
+
/**
|
|
1566
|
+
* Check if a div tag is a valid DOM HTMLElement
|
|
1567
|
+
* @instance
|
|
1568
|
+
* @function isElement
|
|
1569
|
+
* @param {Object} o - The div tag
|
|
1570
|
+
* @return {Boolean} - True if is an element otherwise returns False
|
|
1571
|
+
*/
|
|
1572
|
+
export const isElement = function (o) {
|
|
1573
|
+
return typeof HTMLElement === "object"
|
|
1574
|
+
? o instanceof HTMLElement //DOM2
|
|
1575
|
+
: o &&
|
|
1576
|
+
typeof o === "object" &&
|
|
1577
|
+
o !== null &&
|
|
1578
|
+
o.nodeType === 1 &&
|
|
1579
|
+
typeof o.nodeName === "string";
|
|
1580
|
+
};
|
|
1581
|
+
</code></pre>
|
|
1582
|
+
</article>
|
|
1583
|
+
</section>
|
|
1584
|
+
|
|
1585
|
+
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
</div>
|
|
1591
|
+
|
|
1592
|
+
<br class="clear">
|
|
1593
|
+
|
|
1594
|
+
<footer>
|
|
1595
|
+
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.7</a> using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
|
|
1596
|
+
</footer>
|
|
1597
|
+
|
|
1598
|
+
<script>prettyPrint();</script>
|
|
1599
|
+
<script src="scripts/polyfill.js"></script>
|
|
1600
|
+
<script src="scripts/linenumber.js"></script>
|
|
1601
|
+
|
|
1602
|
+
<script src="scripts/search.js" defer></script>
|
|
1603
|
+
|
|
1604
|
+
|
|
1605
|
+
<script src="scripts/collapse.js" defer></script>
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
</body>
|
|
1609
|
+
</html>
|