-
-
Notifications
You must be signed in to change notification settings - Fork 716
Make 3D SobelOperator consistent with 2D, add UseLegacyCoefficients, add ND support #5718
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
base: main
Are you sure you want to change the base?
Make 3D SobelOperator consistent with 2D, add UseLegacyCoefficients, add ND support #5718
Conversation
dzenanz
left a comment
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.
Did we have dimensionality constraints somewhere? If so, we should lift them as part of this PR. Also, we probably want to add unit tests for higher dimensions.
Thanks for the reminder 😺 We would also have to generalize its
So you see, it's really WIP! |
54d23a1 to
730a117
Compare
|
FYI My intention is to squash most of these WIP commits before making the PR ready for review. (But before doing so, the PR should also offer a backward compatible legacy option, at least for 3D.) |
|
/azp run ITK.Linux.Python |
|
/azp run ITK.Linux |
6ad490d to
4c20b2c
Compare
| const auto & kernel = sobelKernels[VDimension - 1 - direction]; | ||
| return CoefficientVector(kernel.cbegin(), kernel.cend()); |
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.
Why not simply kernel = sobelKernels[direction]? I still don't understand why the kernels returned by the AI generated function from #5702 (comment) are in the reverse order, compared by ITK 🤷
4c20b2c to
a20d509
Compare
|
When I am building SimpleITK with Elastic against the current ITK main ( or work derived from ). I am getting the following compilation error: Will this PR fix this issue? |
Because this PR is already so elaborate, I would prefer to have the fix in a follow-up. This PR aims to:
The follow-up PR should then:
If SimpleITK does not need 4D Sobel, better just not wrap it at all! It never worked anyway. In the past, it just produced an exception. Update: this PR now includes 4-D support! No need to wait for a follow-up 😃 |
The error comes from elastix usage of the Sobel operator: Should I wait for this PR and subsequent to fix Elastix or update the Elastic version in SimpleITK? Or something else? |
| void | ||
| UseLegacyCoefficients(const bool useLegacyCoefficients) | ||
| { | ||
| m_UseLegacyCoefficients = useLegacyCoefficients; | ||
| } |
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.
Note that itkSetMacro(UseLegacyCoefficients, bool) does not compile, because itk::SobelOperator is not derived from itk::Object, and it does not support this->Modified().
The macro (itkSetMacro) would make it SetUseLegacyCoefficients(bool _arg) instead. But I think UseLegacyCoefficients(const bool useLegacyCoefficients) is more readable. OK?
What about the other member function, IsUsingLegacyCoefficients()? Is that clear enough?
a20d509 to
873d1df
Compare
The old kernel coefficients for 3D appeared inconsistent with the coefficients for 2D. This commit allows generating these coefficients consistently, inspired by the AI generated function `make_nd_sobel_kernels`, presented by Hans Johnson at issue InsightSoftwareConsortium#5702 The new coefficients are more commonly used by other toolkits, including SciPy's `scipy.ndimage.sobel`, and correspond with https://en.wikipedia.org/wiki/Sobel_operator This commit removes the reference to "An Isotropic 3x3x3 Volume Gradient Operator", Sobel, 1995, as it cannot be found anymore. Added a `UseLegacyCoefficients` option to SobelOperator, allows the user to specify whether or not `SobelOperator::GenerateCoefficients()` should still produce the old coefficients for a 3D kernel. Enabled by default.
873d1df to
43801b2
Compare
Removed the `static_assert` from `SobelOperator` that allowed only 2D and 3D. Added checks for 1D and 4D to the `SobelOperator.CheckKernelCoordinates` unit test. Addresses issue InsightSoftwareConsortium#5702 "A ND Sobel implementation is needed."
@dzenanz Addressed by the last commit: ENH: Add ND support to SobelOperator |
@blowekamp My formal answer (however disappointing) is of course: Elastix does not support arbitrary revisions of ITK. It only supports official releases of ITK. (Elastix might occasionally support an alpha or a beta version of ITK, but we try to stick to official releases. Not an arbitrary revision from the |
|
My post at discourse.itk.org about this pull request: Sobel operator extended for 4D, legacy support for 3D, OK? |
dzenanz
left a comment
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 have not dived into the AI generated nD code, but it looks simple. You added 4D test. Can you add 5D test? Possibly by using coefficients from SciPy, or someplace else that has them. That would increase our confidence in this code. But good even as is.
|
@dzenanz Partially in response to your comment, the proposed new coefficients from this PR can be produced using SciPy, as follows: import scipy
import numpy as np
def print_sobel(input):
for itk_direction in range(np.ndim(input)):
axis = np.ndim(input) - itk_direction - 1
print(np.flip(scipy.ndimage.sobel(input, axis), axis).flatten())
input_2d = np.zeros((3, 3), dtype=int)
input_2d[1, 1] = 1
print_sobel(input_2d)
input_3d = np.zeros((3, 3, 3), dtype=int)
input_3d[1, 1, 1] = 1
print_sobel(input_3d)Output: |
|
For 5D, the expected coefficients are as follows. I doubt if it makes things clearer when copy-pasting all those numbers into the unit test 🤷 |
|
Putting it into a unit tests makes sure that the new implementation is working as expected, and prevents future regressions. You can put the code which produced the coefficients in a comment above it. |
The proposed unit test is now testing 1D, 2D, 3D, and 4D. I think that's sufficient for now. When 1D, 2D, 3D, and 4D behave well, I think there is no reason for 5D to misbehave. 🤷 |
|
Then merge. Unless you are expecting reviews from more people. |
|
@hjmjohnson Do you agree that this PR properly solves your issue #5702 |
|
For the record: Below here some nice pictures of the kernels of a 3D Sobel operator, as posted by Sven Fritsch at https://stackoverflow.com/a/66698671. Their values appear to correspond with the proposed new coordinates for a 3D
|



The old kernel coefficients for 3D appeared inconsistent with the coefficients for 2D. This pull request allows generating these coefficients consistently, inspired by the AI generated function
make_nd_sobel_kernels, presented by Hans Johnson (@hjmjohnson) at #5702 (comment)The new coefficients are more commonly used by other toolkits, including SciPy's
scipy.ndimage.sobel, and correspond with https://en.wikipedia.org/wiki/Sobel_operatorThis PR removes the reference to "An Isotropic 3x3x3 Volume Gradient Operator", Irwin Sobel, 1995, as it cannot be found anymore.
Added a
UseLegacyCoefficientsoption to SobelOperator, which allows the user to specify whether or notSobelOperator::GenerateCoefficients()should still produce the old coefficients for a 3D kernel. Enabled by default.Removed the
static_assertfromSobelOperatorthat allowed only 2D and 3D. Added checks for 1D and 4D to the unit test.