itk-wasm
itk-wasm copied to clipboard
WIP: Dicom Parsing Example Proof-of-Concept
Early work in progress showcasing an example that parses and organizes DICOM instances before reading them with ITK.
Opening this PR mainly to enable discussions. I might create a new one once we have a clearer picture of how this will get integrated into ITK (in-source vs npm dependency), dicomParser vs daikon, etc...
Related discussions: itk discourse, #250, #251 cc: @thewtex, @floryst, @zachmullen, @pieper
@pieper would you be able to show me where in dcmjs or OHIF are the instance tags extracted to generate the data necessary for volume visualization (pixel data, spacing, origin, orientation, dimensions, etc...)?
This is how it is done in Girder, leveraging daikon instead of dicom-parser: DicomViewer.vue. It's done slice per slice however (one image data per slice), and there is no 3d space/ z-depth considered.
I believe Slicer does some of that here.
I am asking because the work in this branch can be used to organize patient/study/series and extract the files for a specific series, which are then passed to ITK when are once again read and parsed by DCMTK (with emscripten). Ideally, we would avoid reading and parsing them twice, and just extract the data that matters from the series instead of the list of files: this could then be used as a module by ITK, VTK, Girder, even dcmjs and OHIF if there is any use for it.
Hi @agirault -
It's a complex topic, as you know! Especially the Slicer part, since many cases are handled. Happy to talk if over if that would help.
Yes, for sure we should be treating all of this consistently and efficiently and I appreciate the effort you are putting into it.
We typically rely on the server to sort patient/study/series in the database (e.g. https://github.com/dcmjs-org/dicomweb-server uses CouchDB and Slicer uses SQLite via CTK https://github.com/commontk/CTK/tree/master/Libs/DICOM/Core.)
Once you have the instances for a series, in dcmjs the mapping to volumes is here:
https://github.com/dcmjs-org/dcmjs/blob/master/src/normalizers.js
The idea is that a "normalized" dicom is a multiframe conversion, often referred to as a 'dataset' in the code. This has all the image data in an array that is effectively exactly what ITK and VTK expect as pixel arrays.
Here's the code to map the dataset to a vtkImageData, which is simple as you can see.
https://github.com/dcmjs-org/dcmjs/blob/master/examples/vtkDisplay/index.html#L448-L475
I'm going to put on my opinionated hat here, and say that dcmjs does things the right way. It is my favorite of all the implementations for a lot of reasons (that I'm happy to describe at length if prompted!). In a nutshell dcmjs reflects a more comprehensive perspective on various quantitative imaging use cases.
-Steve
Hi @pieper. Thanks a lot for sharing this.
Once you have the instances for a series, in dcmjs the mapping to volumes is here. The idea is that a "normalized" dicom is a multiframe conversion, often referred to as a 'dataset' in the code. This has all the image data in an array that is effectively exactly what ITK and VTK expect as pixel arrays. I'm going to put on my opinionated hat here, and say that dcmjs does things the right way.
Indeed, it seems dcmjs does it right, and I don't want to reinvent the wheel so I'll hold off on continuing implementing this in this current example.
We typically rely on the server to sort patient/study/series in the database (e.g. dicomweb-server uses CouchDB and Slicer uses SQLite via CTK.)
We need to be able to do this sorting client-side since in our use-case the user uploads DICOM files and selects a series that will be rendered on the client, and eventually sent over to the server afterward. My current proof-of-concept in this branch achieves that by leveraging dicomParser: do you see a way we could integrate that in the dcmjs workflow, to be able to combine the parsing of dicomParser and the dcmjs normalization of the selected series all on the client?
Also worth noting that the current implementation I have in this branch is about 6x (with reslice intercept and/or slope) to 17x faster (without reslice) than the ITK readImageDICOMFileSeries for reading the files, parsing them, and extracting the pixel data as a typed array.
FYI @finetjul @aylward
@agirault sorry for the slow reply, I was out last week.
Regarding the browser-centric workflow I entirely agree. I'd still stick with the database approach to organizing the series though, for consistency. We haven't fleshed it out yet, but I would like to see the same dicomweb-server code applied via PouchDB so that the 'client' side of the browser can use DICOMweb API calls even though it is talking to a local facade.
I agree that doing this in native javascript is a better idea than using cross-compiled C++. Not just for speed, but also because there are a lot of use cases for DICOM that still need work to represent well and there's no reason to limit ourselves to what has been implemented for imaging in the past. We can address more general quantitative imaging tasks like segmentation and annotation more cleanly using the dcmjs approach.
Would you be interested in having a chat sometime to compare notes? There are several projects that probably share some core needs and maybe we can make progress together.
Updated to handle rescale intercept, rescale slope, and masking, and added a chrono to log timings and compare. cc: @thewtex @floryst @aylward
Updated to speed up rescaling and parsing (less function calls, more classic loops), thanks @floryst for the suggestions.
For compatibility with DICOM, AWS, etc, the metadata could be structured similar to the ImageSet metadata described here:
https://github.com/aws-samples/amazon-healthlake-imaging-samples/blob/88666ee00a0830b3a7cab403267887b8ff6de662/pixel-data-verification/index.js#L43-L49