diff --git a/include/itkIsotropicWaveletsUtilities.h b/include/itkIsotropicWaveletsUtilities.h new file mode 100644 index 0000000..5602796 --- /dev/null +++ b/include/itkIsotropicWaveletsUtilities.h @@ -0,0 +1,103 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#ifndef itkIsotropicWaveletsUtilities_h +#define itkIsotropicWaveletsUtilities_h + +#include "itkRieszUtilities.h" +#include "itkWaveletUtilities.h" + +namespace itk +{ +/** + * Utility class for wrappings purposes. + * + * The static functions call the free function versions from + * itkRieszUtilities.h and itkWaveletUtilities.h + * + * From python, it can be used as: + * itk.IsotropicWaveletsUtilities.Factorial(2) + */ +struct IsotropicWaveletsUtilities +{ + using IndexPairType = itk::utils::IndexPairType; + + /// Factorial + static long + Factorial(const long n); + + /** + * Compute number of components p(N, d), where N = Order, d = Dimension. + * p(N,d) = (N + d - 1)!/( (d-1)! N! ) + * + * @param order N of the Riesz transform + * @param dimension d of the image + * + * @return NumberOfComponents given the order for the ImageDimension. + */ + static unsigned int + ComputeNumberOfComponents(const unsigned int & order, const unsigned int & dimension); + + /** Get the (Level,Band) from a linear index output. + * The index corresponding to the low-pass image is the last one, corresponding to the + * IndexPairType(this->GetLevels(), 0). + * + * In a steerable pyramid: TotalOutputs = 1 + Levels * Bands + * + * The outputs are ordered, if n is the \c linearIndex: + * + * n:0 ---> level:0 band:1, + * n:1 ---> l:0, b:2, etc. until b == bands. + * n:bands-1 ---> l:0, b=bands + * + * If there is more than one level: + * + * n:bands ---> l:1, b=1 + * + * if only one level: + * + * n:bands ---> l:0, b=0 + * + * Independently of the numbers of levels or bands, the last index is always the low pass: + * + * nLowPass ---> l:Levels, b=0 + * + * Note that bands and levels are always >= 1. The level/bands returned here corresponds to an index. + */ + static IndexPairType + IndexToLevelBandSteerablePyramid(unsigned int linearIndex, unsigned int levels, unsigned int bands); + + /** Compute max number of levels depending on the size of the image. + * Return J: $ J = \text{min_element}\{J_0,\ldots, J_d\} $; + * where each $J_i$ is the number of integer divisions that can be done with the $i$ size and the scale factor. + * returns 1 if any size is not divisible by the scale factor. + * Size<2> version. + */ + static unsigned int + ComputeMaxNumberOfLevels(const Size<2> & inputSize, const unsigned int & scaleFactor); + /** Compute max number of levels depending on the size of the image. + * Return J: $ J = \text{min_element}\{J_0,\ldots, J_d\} $; + * where each $J_i$ is the number of integer divisions that can be done with the $i$ size and the scale factor. + * returns 1 if any size is not divisible by the scale factor. + * Size<3> version. + */ + static unsigned int + ComputeMaxNumberOfLevels(const Size<3> & inputSize, const unsigned int & scaleFactor); +}; +} // end namespace itk +#endif diff --git a/include/itkWaveletUtilities.h b/include/itkWaveletUtilities.h index 7b776c4..3998ca3 100644 --- a/include/itkWaveletUtilities.h +++ b/include/itkWaveletUtilities.h @@ -34,16 +34,27 @@ namespace utils using IndexPairType = std::pair; /** Get the (Level,Band) from a linear index output. - * The index corresponding to the low-pass image is the last one, corresponding to the IndexPairType(this->GetLevels(), - * 0). In a steerable pyramid: TotalOutputs = 1 + Levels * Bands The outputs are ordered, if n is the \c linearIndex: + * The index corresponding to the low-pass image is the last one, corresponding to the + * IndexPairType(this->GetLevels(), 0). + * + * In a steerable pyramid: TotalOutputs = 1 + Levels * Bands + * + * The outputs are ordered, if n is the \c linearIndex: + * * n:0 ---> level:0 band:1, * n:1 ---> l:0, b:2, etc. until b == bands. * n:bands-1 ---> l:0, b=bands + * * If there is more than one level: + * * n:bands ---> l:1, b=1 + * * if only one level: + * * n:bands ---> l:0, b=0 + * * Independently of the numbers of levels or bands, the last index is always the low pass: + * * nLowPass ---> l:Levels, b=0 * * Note that bands and levels are always >= 1. The level/bands returned here corresponds to an index. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9e8daf7..d4d9a2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,8 @@ set(IsotropicWavelets_SRCS itkRieszUtilities.cxx itkWaveletUtilities.cxx + # For wrappings purposes + itkIsotropicWaveletsUtilities.cxx ) ### generating libraries itk_module_add_library( IsotropicWavelets ${IsotropicWavelets_SRCS}) diff --git a/src/itkIsotropicWaveletsUtilities.cxx b/src/itkIsotropicWaveletsUtilities.cxx new file mode 100644 index 0000000..ec05959 --- /dev/null +++ b/src/itkIsotropicWaveletsUtilities.cxx @@ -0,0 +1,56 @@ +/*========================================================================= + * + * Copyright NumFOCUS + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#include "itkIsotropicWaveletsUtilities.h" + +namespace itk +{ +long +IsotropicWaveletsUtilities::Factorial(const long n) +{ + return itk::utils::Factorial(n); +} + +unsigned int +IsotropicWaveletsUtilities::ComputeNumberOfComponents(const unsigned int & order, const unsigned int & dimension) +{ + return itk::utils::ComputeNumberOfComponents(order, dimension); +} + +IsotropicWaveletsUtilities::IndexPairType +IsotropicWaveletsUtilities::IndexToLevelBandSteerablePyramid(unsigned int linearIndex, + unsigned int levels, + unsigned int bands) +{ + return itk::utils::IndexToLevelBandSteerablePyramid(linearIndex, levels, bands); +} + + +unsigned int +IsotropicWaveletsUtilities::ComputeMaxNumberOfLevels(const Size<2> & inputSize, const unsigned int & scaleFactor) +{ + return itk::utils::ComputeMaxNumberOfLevels<2>(inputSize, scaleFactor); +} + +unsigned int +IsotropicWaveletsUtilities::ComputeMaxNumberOfLevels(const Size<3> & inputSize, const unsigned int & scaleFactor) +{ + return itk::utils::ComputeMaxNumberOfLevels<3>(inputSize, scaleFactor); +} + +} // end namespace itk diff --git a/wrapping/itkIsotropicWaveletsUtilities.wrap b/wrapping/itkIsotropicWaveletsUtilities.wrap new file mode 100644 index 0000000..e4cb2b9 --- /dev/null +++ b/wrapping/itkIsotropicWaveletsUtilities.wrap @@ -0,0 +1,3 @@ +itk_wrap_class("itk::IsotropicWaveletsUtilities") + itk_wrap_template("IsotropicWaveletsUtilities" "") +itk_end_wrap_class() diff --git a/wrapping/test/CMakeLists.txt b/wrapping/test/CMakeLists.txt index df61a05..44f4538 100644 --- a/wrapping/test/CMakeLists.txt +++ b/wrapping/test/CMakeLists.txt @@ -36,3 +36,5 @@ itk_python_expression_add_test(NAME itkFrequencyExpandViaInverseFFTImageFilterPy EXPRESSION "instance = itk.FrequencyExpandViaInverseFFTImageFilter.New()") itk_python_expression_add_test(NAME itkFrequencyShrinkViaInverseFFTImageFilterPythonTest EXPRESSION "instance = itk.FrequencyShrinkViaInverseFFTImageFilter.New()") +itk_python_expression_add_test(NAME itkIsotropicWaveletsUtilitiesPythonTest + EXPRESSION "itk.IsotropicWaveletsUtilities.Factorial(2)")