-
Notifications
You must be signed in to change notification settings - Fork 439
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
Add points_to_cells
and cells_to_points
ImageDataFilters
#6071
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #6071 +/- ##
=======================================
Coverage 96.99% 96.99%
=======================================
Files 141 141
Lines 24647 24691 +44
=======================================
+ Hits 23906 23950 +44
Misses 741 741 |
@pyvista-bot preview |
pyvista/core/filters/image_data.py
Outdated
However, this does not visually show the correct representation when point data | ||
is used to represent the centers of voxels. In this case we can convert the | ||
point data to cell data to create a cell-based representation of the voxels. |
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 was reading the documentation and needed help understanding the process that is taking place here. Are you calculating the average of the data of the points in the cell and making it the data of the cell?
However, I would like to be able to understand the process that is being done just by reading the documentation. Therefore, I am writing my impressions without reading the code.
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 actual point or cell data is not modified at all. It is passed through without modification.
The conversion is completely lossless in that regard. It is possible to convert the point voxels to cell voxels and back any number of times and the data will remain the same.
What this filter does is simply change how voxels are represented in terms of the actual ImageData container itself.
Basically, the filter simply modifies the container (I.e the ImageData itself, not the point or cell data), to change what the "definition" of a voxel is.
Many image libraries define an image as follows, for example:
In this case, the image is defined as an array of pixel cells, but the point data of the image is the center of the pixel (or voxel). So, in this case, a pixel or voxel is fundamentally "a point in the center of a pixel cell". Generally, when working with an array of point data, the points themselves represent the center points of the pixels or voxels.
This contrasts with how VTK fundamentally defines ImageData, where the points are the "corners" of cells, not the cell centers. So, if I have a single point voxel, what I really have is a point in the center of vtk Voxel Cell. So in order to correctly represent a single voxel point , I actually need a single vtk Voxel Cell. The confusing part is that this now means that I need 8 points (of the Voxel Cell) to represent the single point voxel that I actually have (which is at the center of the cell).
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.
If I have scalar data for a single voxel (an abstract voxel, not a vtk voxel cell), there are two distinct representations I can use. Both are valid representations but have different uses depending on the filter or application.
1: Represent this as a single vtk point, with a point data array of length one
2: Represent this as a single vtk voxel cell, with a cell data array of length one.
If you'd like I can provide more concrete examples using specific filters to demonstrate what I mean and show why the filters from this PR are useful.
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.
For additional context about the notion of pixels as cells vs pixels as points, and the confusion surrounding it in VTK, see the vtk discourse discussion about it here:
https://discourse.vtk.org/t/proposal-to-add-orientation-to-vtkimagedata-feedback-wanted/120/44
Only the linked comment, and the replies after it are relevant (the rest of the discussion is about image orientation)
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.
This quote from Ken Martin summarizes what this PR does very nicely.
"People tend to expect 100 pixels at 1mm per pixel to create an image of 100mm, but in VTK 100 point samples on an axis equals 99 cells on an axis. And when you draw those cells they look like 99 pixels when people expect 100. I think moving to cell data for pixels would get us to a more common representation. The image would have 100 pixels of cell data, 100 cells, and 101 points defining the boundary of those cells (on an axis)."
point_voxels_to_cell_voxels
will make it so that 100 point samples (with 99 cells) becomes 100 cells with 101 points.
cell_voxels_to_point_voxels
does the reverse.
In either case, the data itself is the same, it's just a matter of representation. And this difference in representation will impact how the filter processes the data. If the wrong representation is used, this can give incorrect or unexpected results with some filters.
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. That was a very clear explanation. I will merge once #6071 (comment) is resoleved.
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.
Great, I will rename the filters and push the updates soon, within the next day or so
point_voxels_to_cell_voxels
and cell_voxels_to_point_voxels
ImageDataFilterspoints_to_cells
and cells_to_points
ImageDataFilters
@pyvista-bot preview |
This looks really useful. I haven't looked at the code in detail, but it is my impression that the other kind of data would be discarded completely? For example, I have
|
Good point, yes this is correct, the 'other' data is lost. It was previously documented, e.g. for
Do you mean to add more information to the See Also sections just to make it clear what the differences are and/or make it clear why these other methods are linked?
I like the term "remeshing". I wasn't sure if I should use the word "convert", "transform", "modify", etc... I think perhaps "remeshing" should be used in the docs instead. Let me know if you agree, any input to make this method as clear as possible is very helpful. |
If it can be stated succinctly, it makes sense to me to have in See Also. I think these methods will get confused unless directly compared/contrasted. I personally like |
@pyvista-bot preview |
I'd vote for In a cartographic context Using these two terms (do we have a glossary?) consistently throughout the codebase and docs would be helpful, if you all agree with what they mean. |
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 don't have time for a full review of this, but the parts I mentioned before look good to me. Thanks!
@pyvista-bot preview |
@pyvista-bot preview |
@pyvista-bot preview |
@pyvista-bot preview |
@pyvista-bot preview |
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.
LGTM
@pyvista-bot preview |
Overview
Add two new complimentary ImageDataFilters for converting how voxel data is represented.
Voxels for images are often represented as points with point data. But, confusingly, converting image data (with point voxels) to an unstructured grid or using pretty much any cell-based DataSet filter (e.g. threshold) will perform the operation on the voxel cells of the image data, not the points. This can result in unexpected output, e.g. a 2x2x2 array of voxel points, when cast to an unstructured grid, will be visually represented as a single voxel cell instead of the 8 input voxel points.
Using the filters from this PR enables the points to first be converted to voxel cells so that cell-based operation will generate the expected output.
This is a follow-up from #5968. Since the internal vtk filter for that PR requires voxel point data, the conversion filters from this PR will enable any inputs, with either point or cell data , to be used with that filter (i.e. cell data is first converted to point data using
cell_voxels_to_point_voxels
.