Skip to content
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

ENH: Improve Thresholding module filters' coverage. #511

Conversation

jhlegarreta
Copy link
Member

@jhlegarreta jhlegarreta commented Feb 16, 2019

Improve the ITKThresholding module filters' coverage:

  • Exercise basic object methods. Remove redundant calls to print the
    filter.
  • Exercise the Set/Get methods using the TEST_SET_GET_VALUE and On/Off
    methods using the TEST_SET_GET_BOOLEAN macro.
  • Use the TRY_EXPECT_NO_EXCEPTION macro for all filter update calls to
    save typing try/catch blocks.
  • Use TRY_EXPECT_EXCEPTION to try/catch expected exceptions when
    possible/appropriate.
  • Refactor the tests to accept (more) input parameters to check the
    classes under a broader range of conditions. In many cases, the
    parameters accepted belong to inherited propertis (e.g.
    itk::HistogramThresholdImageFilter: m_NumberOfHistogramBins,
    m_AutoMinimumMaximum, m_MaskOutput, m_MaskValue). Keep the default
    values of the class for existing tests.
  • Make the tests quantitative: compare the compute threshold to the
    expected one.
  • Add the hash code to compare to the baseline for new tests.
  • Remove unnecessary print messages.
  • Style changes: define the image dimension as a constant; use a typedef
    for the pixel type; use a variable to set the output's inside/outside
    value so that its Set/Get methods can be clearly tested; try to use the
    same sequence of sentences across all tests; change '\n' to std::endl.
  • Improve the messages in the threshold regression tests to make the
    consistent across the tests/the entire toolkit, and to provide rich
    information.
  • Finished the tests with a "Test finished" message; helps telling in the
    the dashboard whether the failure has happened in the test or the
    comparison to the baseline.
  • In itkBinaryThresholdImageFilterTest.cxx, set the functor before
    updating the filter.
  • Correct the arguments passed to SetSigmaFactor and SetNumberOfIterations
    in itkKappaSigmaThresholdImageFilterTest.cxx (the expected sigmaFactor
    as defined by the order in the CMakeLists command/usage explanation was
    being set to the number of iterations of the filter and vice-versa).
    Update the corresponding baselines accordingly.

Take advantage of the commit to use C++11 features.

Recovered from gerrit:
Change-Id: I9d6050d9e474b17fe3639faa7a5b16c052440e21
https://review.source.kitware.com/%23/c/22134/

@jhlegarreta
Copy link
Member Author

I still did not study @richardbeare 's last comment at the time the topic was being reviewed in gerrit. That will take some time.

And there will be a few tests whose baseline needs to be updated.

But this is a starting point as a refactoring and code coverage improvement.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 3233630 to 50e23cb Compare February 16, 2019 21:25
@jhlegarreta jhlegarreta added the type:Coverage Code coverage impacts label Feb 23, 2019
@jhlegarreta
Copy link
Member Author

Just as a follow-up, generating all baselines and updating/adding them will take me quite some time.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 50e23cb to be4985e Compare March 30, 2019 04:12
@jhlegarreta
Copy link
Member Author

Rebased on master to fix the merge conflicts. Have not yet reproduced the test results.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from be4985e to 58582ad Compare March 30, 2019 13:48
@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 58582ad to 9eb112d Compare May 11, 2019 18:18
@jhlegarreta
Copy link
Member Author

Rebased on master to avoid further conflicts when I find the time to review the topic.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 9eb112d to a6b148f Compare May 26, 2019 20:54
@jhlegarreta
Copy link
Member Author

a6b148f rebased on master and addressed KWStyle warnings. Working on the baselines.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from a6b148f to 484290c Compare May 27, 2019 03:03
@jhlegarreta
Copy link
Member Author

A few comments about 484290c:

  • Undoing some style changes done in a6b148f that generated build errors.
  • KW Style is generating a few error: Unnecessary semicolon false negatives. Still producing some locally at itkHistogramThresholdImageFilter:205 and itkHistogramThresholdImageFilter:207.
  • Add missing baselines and fix the corresponding content links in the CMakeLists.txt file.
  • Fix some expected values in the script tests.
  • Change a TRY_EXPECT_EXCEPTION oversight to TRY_EXPECT_NO_EXCEPTION.
  • Fix a test output filename.
  • itkIntermodesThresholdImageFilterTestNoAutoMinMax failing locally because the itk::IntermodesThresholdCalculator instance is exceeding the maximum iterations for histogram smoothing.
  • itkMaximumEntropyThresholdImageFilterTestNoAutoMinMax producing a vector subscript out of range error because the itk::Historam::GetMeasurement method's InstanceIdentifier parameter has a value of 18446744073709551615.
  • itkShanbhagThresholdImageFilterTestNoAutoMinMax producing a vector subscript out of range at the itk::Historam::GetMeasurement method because the m_Min and m_Max variables are not initialized.
  • Not sure about the itkOtsuThresholdImageFilterTestNoAutoMinMax test being deterministic any more.
  • I have removed the null calculator exception test from itkOtsuThresholdImageFilterTestNoAutoMinMax because it no longer throws such an exception after 79148b6.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 484290c to 09dd192 Compare May 27, 2019 23:37
@jhlegarreta
Copy link
Member Author

The remaining errors are due to the causes explained above, which dot not look evident, so it will take some time to find the appropriate fixes.

@fbudin69500
Copy link
Contributor

Did a quick first pass review. Looks good. I will do a more in-depth review when the tests pass.

@jhlegarreta
Copy link
Member Author

@fbudin69500 thanks for having a look.

I started to have another look at the IntermodesThresholdImageFilter failures.

Well, it seems to be trickier than what it looks like. I'd dare to say that there is some sort of inheritance mess involved.

When running the TRY_EXPECT_EXCEPTION( filter->Update() ); statement right after the call to SetMaximumSmoothingIterations in the test, the progress reporter std output shows the filter as being upcasted to its parent class.

If I reimplement the SetCalculator function in itk::IntermodesThresholdImageFilter, and lower the maximum number of iterations (it reaches 14 when finishing the process) and set it to 10 in the test), the exception is indeed caught, but the exception is not quite itkIntermodesThresholdCalculator.hxx:100, but the one in itkHistogramThresholdImageFilter.hxx:67.

So there is some sort of inheritance issue: the itk::IntermodesThresholdImageFilter class uses a specialized itk::itkIntermodesThresholdCalculator class, with an ivar of its own, but the former still uses its parent method's (e.g. GenerateData) which has no idea about the itk::itkIntermodesThresholdCalculator ivar.

To be honest, I've spent some time trying to find an accurate explanation in order to propose a solution, but the best explanation I've come up to is the above, and still have not found a fix.

@jhlegarreta
Copy link
Member Author

Rebased on master after #999 has been merged.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch 3 times, most recently from a7b9d73 to a95d5f6 Compare June 11, 2019 00:07
@stale
Copy link

stale bot commented Oct 9, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
jhlegarreta added a commit to jhlegarreta/ITK that referenced this pull request Mar 23, 2020
…shold

Fix the threshold calculator inheritance issue in
`itk::IntermodesThresholdImageFilter` by having a single histogram
threshold calculator variable.

The class was declaring a histogram threshold calculator under the
`m_IntermodesCalculator` ivar, which was of type
`itk::IntermodesThresholdCalculator` type. At the same time, the class was
inheriting from `itk::HistogramThresholdImageFilter`, which was declaring
its own histogram threshod calculator `m_Calculator`, which was of type
`itk::HistogramThredholdCalculator`.

This was making the `itk::IntermodesThresholdImageFilter` objects to have
two histogram calculator instances, and given that the `GenerateData`
method was implemented in the parent class
(`itk::HistogramThresholdImageFilter`) and making use of the
`m_Calculator` ivar, this was yielding a runtime error.

Fixes the runtime exception error mentioned in [this
comment](InsightSoftwareConsortium#511 (comment)).
@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch 4 times, most recently from 163fa27 to 891898d Compare March 29, 2020 00:08
@jhlegarreta jhlegarreta changed the title WIP: ENH: Improve Thresholding module filters' coverage. ENH: Improve Thresholding module filters' coverage. Mar 29, 2020
@jhlegarreta
Copy link
Member Author

jhlegarreta commented Mar 29, 2020

Folks, we are getting closer. A few comments:

  • I could not make work two tests locally:
    • itkIntermodesThresholdImageFilterTestNoAutoMinMax gets stuck at progress 0.8 whatever the maximum number of smoothing iterations (I've gone up to 8000000). It is not related to the change in ENH: Avoid duplicated code in itk::HistogramThresholdImageFilter #1732 (I've checked that the same happens with the code prior to the commit in that PR).
    • itkOtsuThresholdCalculatorVersusOtsuMultipleThresholdsCalculatorTest fails when comparing the values of the values yielded by itk::OtsuThresholdsCalculator and the itk::OtsuMultipleThresholdsCalculator instances.

I had a look at both issues without success. To be honest, if nobody has the bandwidth to address them in the following days (I personally don't) I'd comment both tests and open two issues so that the PR can be merged (if the rest of the tests pass).

  • When setting the autoMinimumMaximum flag to false, all thresholding filters return the same threshold value (provided that the input image is the same), e.g. -31744 for cthead1.png. Checking the range of the input image values, this expected threshold value seems to be in the lower end of the dynamic range. I have not dug more than that, but my impression is that it is like a floor value of the histogram. Also, the output image contains a single value (they appear completely black). I'd dare to say that this makes sense since the histogram filter was told not to compute any limits. Now to solve this we should be able to set those limits manually (e.g. find the filtering thresholds between the itk::HistogramThresholdImageFilter::m_Minimum and itk::HistogramThresholdImageFilter::m_Maximum arbitrary values e.g. 100 and 1340 -the filter should internally make sure they are not out of bounds). This means that we should be able to set those numbers or that filter to our thresholding filter (e.g. itk::MaximumEntropyThresholdImageFilter), instead of the autoMinimumMaximum flag maybe or using some logic in case the flag is set to false. And we should be able to set those values in the tests where the flag is set to false. That is not possible now, and requires some work both on the classes and the tests. Honestly, I would open an issue and let whoever has the bandwith to fix it.
  • Note that I did not have a close look at whether all tests had nice parameters so as to have a meaningful output (e.g. itkOtsuThresholdImageFilterTestShort generates a thresholded output which is not really meaningful/useful). So maybe an issue could be opened to identify those tests so that anybody who has time can play with the parameters to get nice thresholding results and modify the tests accordingly.

TLDR: If only itkIntermodesThresholdImageFilterTestNoAutoMinMax itkOtsuThresholdCalculatorVersusOtsuMultipleThresholdsCalculatorTest fail, I will comment the tests and open the appropriate issues.

Sorry for the length of the message.

@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 891898d to 632d5de Compare March 29, 2020 00:43
@jhlegarreta
Copy link
Member Author

CI results are as anticipated in this comment. Please consider reading it and comment as appropriate. Thanks !

Copy link
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with those two tests commented in CMakeLists.txt, this is a big improvement. Hopefully it will nudge somebody to look into those two tests too.

Improve the ITKThresholding module filters' coverage:
- Exercise basic object methods. Remove redundant calls to print the
  filter.
- Exercise the Set/Get methods using the TEST_SET_GET_VALUE and On/Off
  methods using the TEST_SET_GET_BOOLEAN macro.
- Use the TRY_EXPECT_NO_EXCEPTION macro for all filter update calls to
  save typing try/catch blocks.
- Use TRY_EXPECT_EXCEPTION to try/catch expected exceptions when
  possible/appropriate.
- Refactor the tests to accept (more) input parameters to check the
  classes under a broader range of conditions. In many cases, the
  parameters accepted belong to inherited propertis (e.g.
  itk::HistogramThresholdImageFilter: m_NumberOfHistogramBins,
  m_AutoMinimumMaximum, m_MaskOutput, m_MaskValue). Keep the default
  values of the class for existing tests.
- Make the tests quantitative: compare the compute threshold to the
  expected one.
- Add the hash code to compare to the baseline for new tests.
- Remove unnecessary print messages.
- Style changes: define the image dimension as a constant; use a typedef
  for the pixel type; use a variable to set the output's inside/outside
  value so that its Set/Get methods can be clearly tested; try to use the
  same sequence of sentences across all tests; change '\n' to std::endl.
- Improve the messages in the threshold regression tests to make the
  consistent across the tests/the entire toolkit, and to provide rich
  information.
- Finished the tests with a "Test finished" message; helps telling in the
  the dashboard whether the failure has happened in the test or the
  comparison to the baseline.
- In itkBinaryThresholdImageFilterTest.cxx, set the functor before
  updating the filter.
- Correct the arguments passed to SetSigmaFactor and SetNumberOfIterations
  in itkKappaSigmaThresholdImageFilterTest.cxx (the expected sigmaFactor
  as defined by the order in the CMakeLists command/usage explanation was
  being set to the number of iterations of the filter and vice-versa).
  Update the corresponding baselines accordingly.

Take advantage of the commit to use C++11 features.

Recovered from gerrit:
Change-Id: I9d6050d9e474b17fe3639faa7a5b16c052440e21
https://review.source.kitware.com/%23/c/22134/
@jhlegarreta jhlegarreta force-pushed the ImproveThresholdingFiltersCoverage branch from 632d5de to e450780 Compare March 31, 2020 21:08
@jhlegarreta
Copy link
Member Author

So I commented the two failing tests and push-forced.

If CIs still pass, this will be ready to be merged. I will open the related issues once it gets merged.

Thanks.

@jhlegarreta
Copy link
Member Author

Not sure why Azure builds have not been reported. Anybody with the appropriate permissions to trigger those? Thanks.

@dzenanz
Copy link
Member

dzenanz commented Mar 31, 2020

Occasionally they don't report. A force push with updated time should trigger them.

Copy link
Member

@dzenanz dzenanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this improvement!

Copy link
Member

@thewtex thewtex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work, Jon Haitz!

@jhlegarreta
Copy link
Member Author

Thank you all your bearing with the multiple unsuccessful commits and my intermittent dedication. This was team work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:Coverage Code coverage impacts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants