Skip to content

Commit

Permalink
ENH: Increase coverage for itk::SobelOperator
Browse files Browse the repository at this point in the history
Increase coverage for `itk::SobelOperator`:
- Exercise basic object methods using the
  `ITK_EXERCISE_BASIC_OBJECT_METHODS` macro.
- Test the Set/Get methods using the `ITK_TEST_SET_GET_VALUE` macro.

Test the operator using fundametal convolutional operations and using
the `itk::NeighborhoodOperatorImageFilter` filter: ensure that both
yield the same result.

Add the accompanying content data link files.
  • Loading branch information
jhlegarreta authored and dzenanz committed Nov 7, 2022
1 parent 634fa3c commit c86fd78
Show file tree
Hide file tree
Showing 6 changed files with 324 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ad8d58bef453f0d94c9d3b2e32e77b7c1525857a32574372bdc3f7548819c84536674a1ebd5c69e1130e25b2ece46439a53515c3f06ddc13a3eab6e97ed15f9b
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aacd785af92c0b70d58228079a129bf341d2eeee12acaec11c6c7ce91a7dc04b7fe51f92602f86cf9fb2e64beebeb95d4980af9a533ed1d07bcbdf8c99d8d405
21 changes: 21 additions & 0 deletions Modules/Core/Common/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ itkSpatialOrientationTest.cxx
itkStdStreamStateSaveTest.cxx
itkVersionTest.cxx
VNLSparseLUSolverTraitsTest.cxx
itkSobelOperatorImageConvolutionTest.cxx
itkSobelOperatorImageFilterTest.cxx
itkSobelOperatorTest.cxx
)
set(ITKCommon2Tests
itkSTLThreadTest.cxx
Expand Down Expand Up @@ -273,6 +276,24 @@ itk_add_test(NAME itkSpatialOrientationTest COMMAND ITKCommon1TestDriver itkSpat
itk_add_test(NAME VNLSparseLUSolverTraitsTest COMMAND ITKCommon1TestDriver VNLSparseLUSolverTraitsTest)
itk_add_test(NAME itkGaussianDerivativeOperatorTest
COMMAND ITKCommon1TestDriver itkGaussianDerivativeOperatorTest)
itk_add_test(NAME itkSobelOperatorImageConvolutionHorizTest
COMMAND ITKCommon1TestDriver
--compare DATA{Baseline/itkSobelOperatorImageHorizTest.png} ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageConvolutionHorizTest.png
itkSobelOperatorImageConvolutionTest DATA{${ITK_DATA_ROOT}/Input/sf4.png} 0 ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageConvolutionHorizTest.png)
itk_add_test(NAME itkSobelOperatorImageFilterHorizTest
COMMAND ITKCommon1TestDriver
--compare DATA{Baseline/itkSobelOperatorImageHorizTest.png} ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageConvolutionHorizTest.png
itkSobelOperatorImageFilterTest DATA{${ITK_DATA_ROOT}/Input/sf4.png} 0 ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageFilterHorizTest.png)
itk_add_test(NAME itkSobelOperatorImageConvolutionVertTest
COMMAND ITKCommon1TestDriver
--compare DATA{Baseline/itkSobelOperatorImageVertTest.png} ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageConvolutionVertTest.png
itkSobelOperatorImageConvolutionTest DATA{${ITK_DATA_ROOT}/Input/sf4.png} 1 ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageConvolutionVertTest.png)
itk_add_test(NAME itkSobelOperatorImageFilterVertTest
COMMAND ITKCommon1TestDriver
--compare DATA{Baseline/itkSobelOperatorImageVertTest.png} ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageFilterVertTest.png
itkSobelOperatorImageFilterTest DATA{${ITK_DATA_ROOT}/Input/sf4.png} 1 ${ITK_TEST_OUTPUT_DIR}/itkSobelOperatorImageFilterVertTest.png)
itk_add_test(NAME itkSobelOperatorTest
COMMAND ITKCommon1TestDriver itkSobelOperatorTest)

itk_add_test(NAME itkConstNeighborhoodIteratorTest
COMMAND ITKCommon2TestDriver --redirectOutput ${TEMP}/itkConstNeighborhoodIteratorTest.txt
Expand Down
83 changes: 83 additions & 0 deletions Modules/Core/Common/test/itkSobelOperatorImageConvolutionTest.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*=========================================================================
*
* 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
*
* https://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 "itkConstNeighborhoodIterator.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkNeighborhoodInnerProduct.h"
#include "itkSobelOperator.h"
#include "itkTestingMacros.h"


int
itkSobelOperatorImageConvolutionTest(int argc, char * argv[])
{
if (argc != 4)
{
std::cerr << "Missing parameters." << std::endl;
std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv) << " inputFileName direction outputFileName"
<< std::endl;
return EXIT_FAILURE;
}

constexpr unsigned int Dimension = 2;

using PixelType = unsigned char;
using ImageType = itk::Image<PixelType, Dimension>;

using SobelOperatorType = itk::SobelOperator<PixelType, Dimension>;

using NeighborhoodIteratorType = itk::ConstNeighborhoodIterator<ImageType>;
using IteratorType = itk::ImageRegionIterator<ImageType>;


const auto inputImage = itk::ReadImage<ImageType>(argv[1]);


SobelOperatorType sobelOperator;

auto direction = std::stoul(argv[2]);
sobelOperator.SetDirection(direction);

itk::Size<Dimension> radius;
radius.Fill(1);
sobelOperator.CreateToRadius(radius);

NeighborhoodIteratorType it(radius, inputImage, inputImage->GetRequestedRegion());

auto outputImage = ImageType::New();
outputImage->SetRegions(inputImage->GetRequestedRegion());
outputImage->Allocate(true);

IteratorType out(outputImage, inputImage->GetRequestedRegion());

itk::NeighborhoodInnerProduct<ImageType> innerProduct;

for (it.GoToBegin(), out.GoToBegin(); !it.IsAtEnd(); ++it, ++out)
{
out.Set(innerProduct(it, sobelOperator));
}


itk::WriteImage(outputImage, argv[3]);


std::cout << "Test finished." << std::endl;
return EXIT_SUCCESS;
}
68 changes: 68 additions & 0 deletions Modules/Core/Common/test/itkSobelOperatorImageFilterTest.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*=========================================================================
*
* 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
*
* https://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 "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkNeighborhoodOperatorImageFilter.h"
#include "itkSobelOperator.h"
#include "itkTestingMacros.h"


int
itkSobelOperatorImageFilterTest(int argc, char * argv[])
{
if (argc != 4)
{
std::cerr << "Missing parameters." << std::endl;
std::cerr << "Usage: " << itkNameOfTestExecutableMacro(argv) << " inputFileName direction outputFileName"
<< std::endl;
return EXIT_FAILURE;
}

constexpr unsigned int Dimension = 2;

using PixelType = unsigned char;
using ImageType = itk::Image<PixelType, Dimension>;

using SobelOperatorType = itk::SobelOperator<PixelType, Dimension>;
using FilerType = itk::NeighborhoodOperatorImageFilter<ImageType, ImageType>;

const auto inputImage = itk::ReadImage<ImageType>(argv[1]);


SobelOperatorType sobelOperator;

auto direction = std::stoul(argv[2]);
sobelOperator.SetDirection(direction);

itk::Size<Dimension> radius;
radius.Fill(1);
sobelOperator.CreateToRadius(radius);

auto filter = FilerType::New();

filter->SetInput(inputImage);

filter->SetOperator(sobelOperator);

itk::WriteImage(filter->GetOutput(), argv[3]);


std::cout << "Test finished." << std::endl;
return EXIT_SUCCESS;
}
150 changes: 150 additions & 0 deletions Modules/Core/Common/test/itkSobelOperatorTest.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*=========================================================================
*
* 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
*
* https://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 "itkSobelOperator.h"
#include "itkTestingMacros.h"


int
itkSobelOperatorTest(int, char *[])
{

constexpr unsigned int Dimension2D = 2;
constexpr unsigned int Dimension3D = 3;
constexpr unsigned int Dimension4D = 4;

using PixelType = float;

{
constexpr unsigned int Length = 9;

using SobelOperatorType = itk::SobelOperator<PixelType, Dimension2D>;
SobelOperatorType sobelOperator;

ITK_EXERCISE_BASIC_OBJECT_METHODS((&sobelOperator), SobelOperator, NeighborhoodOperator);


// Horizontal
unsigned long direction = 0;
sobelOperator.SetDirection(direction);
ITK_TEST_SET_GET_VALUE(direction, sobelOperator.GetDirection());

itk::Size<Dimension2D> radius;
radius.Fill(1);
sobelOperator.CreateToRadius(radius);

itk::FixedArray<SobelOperatorType::PixelType, Length> expectedValuesHoriz{
{ -1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, 1.0 }
};

const unsigned int size = sobelOperator.GetBufferReference().size();
for (itk::SizeValueType i = 0; i < size; ++i)
{
ITK_TEST_EXPECT_EQUAL(expectedValuesHoriz[i], sobelOperator[i]);
ITK_TEST_EXPECT_EQUAL(expectedValuesHoriz[i], sobelOperator.GetElement(i));
}

// Vertical
direction = 1;
sobelOperator.SetDirection(direction);
ITK_TEST_SET_GET_VALUE(direction, sobelOperator.GetDirection());

sobelOperator.CreateDirectional();

itk::FixedArray<SobelOperatorType::PixelType, Length> expectedValuesVert{
{ -1.0, -2.0, -1.0, 0.0, 0.0, 0.0, 1.0, 2.0, 1.0 }
};
for (itk::SizeValueType i = 0; i < size; ++i)
{
ITK_TEST_EXPECT_EQUAL(expectedValuesVert[i], sobelOperator[i]);
ITK_TEST_EXPECT_EQUAL(expectedValuesVert[i], sobelOperator.GetElement(i));
}
}

{
constexpr unsigned int Length = 27;

using SobelOperatorType = itk::SobelOperator<PixelType, Dimension3D>;
SobelOperatorType sobelOperator;

unsigned long direction = 0;
sobelOperator.SetDirection(direction);
ITK_TEST_SET_GET_VALUE(direction, sobelOperator.GetDirection());

itk::Size<Dimension3D> radius;
radius.Fill(1);
sobelOperator.CreateToRadius(radius);

itk::FixedArray<SobelOperatorType::PixelType, Length> expectedValuesX{
{ -1.0, 0.0, 1.0, -3.0, 0.0, 3.0, -1.0, 0.0, 1.0, -3.0, 0.0, 3.0, -6.0, 0.0,
6.0, -3.0, 0.0, 3.0, -1.0, 0.0, 1.0, -3.0, 0.0, 3.0, -1.0, 0.0, 1.0 }
};
const unsigned int size = sobelOperator.GetBufferReference().size();
for (itk::SizeValueType i = 0; i < size; ++i)
{
ITK_TEST_EXPECT_EQUAL(expectedValuesX[i], sobelOperator[i]);
ITK_TEST_EXPECT_EQUAL(expectedValuesX[i], sobelOperator.GetElement(i));
}

direction = 1;
sobelOperator.SetDirection(direction);

sobelOperator.CreateDirectional();

ITK_TEST_SET_GET_VALUE(direction, sobelOperator.GetDirection());
itk::FixedArray<SobelOperatorType::PixelType, Length> expectedValuesY{
{ -1.0, -3.0, -1.0, 0.0, 0.0, 0.0, 1.0, 3.0, 1.0, -3.0, -6.0, -3.0, 0.0, 0.0,
0.0, 3.0, 6.0, 3.0, -1.0, -3.0, -1.0, 0.0, 0.0, 0.0, 1.0, 3.0, 1.0 }
};
for (itk::SizeValueType i = 0; i < size; ++i)
{
ITK_TEST_EXPECT_EQUAL(expectedValuesY[i], sobelOperator[i]);
ITK_TEST_EXPECT_EQUAL(expectedValuesY[i], sobelOperator.GetElement(i));
}

direction = 2;
sobelOperator.SetDirection(direction);
ITK_TEST_SET_GET_VALUE(direction, sobelOperator.GetDirection());

sobelOperator.CreateDirectional();

itk::FixedArray<SobelOperatorType::PixelType, Length> expectedValuesZ{
{ -1.0, -3.0, -1.0, -3.0, -6.0, -3.0, -1.0, -3.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 1.0, 3.0, 1.0, 3.0, 6.0, 3.0, 1.0, 3.0, 1.0 }
};
for (itk::SizeValueType i = 0; i < size; ++i)
{
ITK_TEST_EXPECT_EQUAL(expectedValuesZ[i], sobelOperator[i]);
ITK_TEST_EXPECT_EQUAL(expectedValuesZ[i], sobelOperator.GetElement(i));
}
}

{
using SobelOperatorType = itk::SobelOperator<PixelType, Dimension4D>;
SobelOperatorType sobelOperator;

unsigned long direction = 0;
sobelOperator.SetDirection(direction);
itk::Size<Dimension4D> radius;
radius.Fill(1);
ITK_TRY_EXPECT_EXCEPTION(sobelOperator.CreateToRadius(radius));
}

std::cout << "Test finished." << std::endl;
return EXIT_SUCCESS;
}

0 comments on commit c86fd78

Please sign in to comment.