-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pixel encapsulation #312
Pixel encapsulation #312
Conversation
…se the minimum posible size. Consume the input vector intead of using a reference.
…l on how to add the frames, this gives options on how much data is stored at the time
I have done a refactor, to allow different kind of scenarios. In the first scenario, you could use the simplest call. The bad part of this is that at some point, the input frames and the output frames are allocated.
Now if memory is an issue (mostly when dealing with multiframe images) the frames can be processed individually.
And the last way is useful when using rayon
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for continuing this contribution. I like the idea of introducing a more substantial API! But I also feel that there is a lot to improve and fix before it is ready. Please attend to the comments inline.
@Enet4 I have improved the code based on the suggestions. Please let me know if you see more things that can be improved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @dougyau! I have been doing some changes to most of the crates in the DICOM-rs project. In particular, I felt that we would be better served with the pixel data sequence type being declared in the core crate itself, which may subvert some of the decisions made here.
Nevertheless, it is still important and useful to have some mechanisms to turn frames into fragments and vice versa (which we do not have yet), so I do not want to put this pull request to waste! :) Please see the inline comment and let me know if you have any other plans here.
pixeldata/src/encapsulation.rs
Outdated
/// dcm.put(DataElement::new(PIXEL_DATA, OB, encapsulated_pixels)); | ||
/// ``` | ||
#[derive(Debug, Default)] | ||
pub struct EncapsulatedPixels { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The upstream version (master
branch) of dicom_core
now features a pixel data fragment sequence type dicom_core::value::PixelFragmentSequence
, so we want to build up our frames-to-fragments abstraction from this. EncapsulatedPixels
would be removed and PixelFragmentSequence
would be given an impl From<FrameFragments>
.
If there are any good methods that would be important to have in PixelFragmentSequence
, it should be possible to accommodate them there as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a great idea as the API would be simpler.
Currently this code should be compatible with the changes made on upstream. But I do like your proposal.
@Enet4 I have updated the tests and the doc blocks on the PR. |
pixeldata/src/encapsulation.rs
Outdated
use dicom_core::value::Value; | ||
|
||
/// Encapsulate the pixel data of the frames. If fragment_size > 0 it will use 1 fragment per frame. | ||
/// This parameter is ignored for multi frame data, as 1 fragment per frame is required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't that depending on the transfer syntax used?
https://dicom.nema.org/dicom/2013/output/chtml/part05/sect_A.4.html
Whether more than one fragment per frame is permitted or not is defined per Transfer Syntax.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for having a look @ingwinlu. The limitations of this abstraction are known, as it aims to facilitate the constructions in the following scenarios (which I believe are the most common ones):
- Each frame is given a single fragment, as in RLE Lossless and all JPEG-based transfer syntaxes;
- A simple image frame is split into multiple fragments.
With that said, there is probably a better way to describe this function in a way which does not confuse API consumers, maybe by having a signature encapsulate_single_frame(frame: Vec<u8>, max_fragment_size: u32) -> Value
instead. Unless it happens that the current function is convenient for both situations, because otherwise it may become a source of confusion that fragment_size
is ignored when more than one frame is passed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to have 1 function for this, otherwise when you intend to encapsulate you need to verify if it is single or multi frame, then call the corresponding function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a few more suggestions. Primarily, I think it makes sense to split encapsulate
for the two key scenarios (unless there is a reason I haven't grasped yet). encapsulate_single_frame
would receive a single frame and a maximum fragment size, whereas the other encapsulate_frames
would give each frame its own fragment and provide a basic offset table accordingly.
core/src/value/fragments.rs
Outdated
/// Represents the fragments of a single frame. [PixelFragmentSequence] can be generated from a list | ||
/// of [Fragments]. In case of multi frame a list of frames composed by 1 fragment is expected. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I usually prefer adding backticks when referring to other types.
The first paragraph is dedicated as a the type's short description.
/// Represents the fragments of a single frame. [PixelFragmentSequence] can be generated from a list | |
/// of [Fragments]. In case of multi frame a list of frames composed by 1 fragment is expected. | |
/// Represents the fragments of a single frame. | |
/// | |
/// A [`PixelFragmentSequence`] can be generated from a list of [`Fragments`]. | |
/// In case of multi-frame, a list of frames composed by 1 fragment is expected. |
pixeldata/src/encapsulation.rs
Outdated
use dicom_core::value::Value; | ||
|
||
/// Encapsulate the pixel data of the frames. If fragment_size > 0 it will use 1 fragment per frame. | ||
/// This parameter is ignored for multi frame data, as 1 fragment per frame is required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for having a look @ingwinlu. The limitations of this abstraction are known, as it aims to facilitate the constructions in the following scenarios (which I believe are the most common ones):
- Each frame is given a single fragment, as in RLE Lossless and all JPEG-based transfer syntaxes;
- A simple image frame is split into multiple fragments.
With that said, there is probably a better way to describe this function in a way which does not confuse API consumers, maybe by having a signature encapsulate_single_frame(frame: Vec<u8>, max_fragment_size: u32) -> Value
instead. Unless it happens that the current function is convenient for both situations, because otherwise it may become a source of confusion that fragment_size
is ignored when more than one frame is passed.
…ames are handled by separately
The changes have been implemented. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, we are in condition to bring this upstream. Thank you @dougyau for your commitment.
Add the function to encapsulate a vector of frames. The function will return a PixelSequence which can be used with DataElement::new() to add the tag to the dataset.