Skip to content

Commit

Permalink
ENH: Add example, "Generate the Offsets of a Shaped Image Neighborhood"
Browse files Browse the repository at this point in the history
  • Loading branch information
N-Dekker authored and dzenanz committed Sep 26, 2022
1 parent a9d3b22 commit 06cc158
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Core/Common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ add_example(DuplicateAnImage)
add_example(ApplyAFilterOnlyToASpecifiedRegionOfAnImage)
add_example(IterateOverARegionWithAShapedNeighborhoodIterator)
add_example(IterateOverARegionWithAShapedNeighborhoodIteratorManual)
add_example(GenerateOffsetsShapedImageNeighborhood)
add_example(CreateABackwardDifferenceOperator)
add_example(BuildAHelloWorldProgram)
add_example(TraceMemoryBetweenPoints)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.16.3)

project(Shapes)

find_package(ITK REQUIRED)
include(${ITK_USE_FILE})

add_executable(${PROJECT_NAME} Code.cxx)
target_link_libraries(${PROJECT_NAME} ${ITK_LIBRARIES})

install(TARGETS ${PROJECT_NAME}
DESTINATION bin/ITKSphinxExamples/Core/Common
COMPONENT Runtime
)

install(FILES Code.cxx CMakeLists.txt
DESTINATION share/ITKSphinxExamples/Code/Core/Common/${PROJECT_NAME}
COMPONENT Code
)

enable_testing()
add_test(NAME ${PROJECT_NAME}Test
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${PROJECT_NAME})
109 changes: 109 additions & 0 deletions src/Core/Common/GenerateOffsetsShapedImageNeighborhood/Code.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*=========================================================================
*
* 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 "itkConnectedImageNeighborhoodShape.h"
#include "itkImage.h"
#include "itkImageBufferRange.h"
#include "itkImageNeighborhoodOffsets.h"
#include "itkRectangularImageNeighborhoodShape.h"
#include "itkShapedImageNeighborhoodRange.h"

#include <array>
#include <cassert>
#include <numeric> // For iota
#include <ios> // For hex

namespace
{
constexpr unsigned int Dimension{ 2 };
using OffsetType = itk::Offset<Dimension>;

// Print the specified offsets of a neighborhood shape. Also prints the pixel values of a small image for which such a
// shaped neigborhood located at the image center is filled with consecutive values, 1, 2, 3, ..., N.
template <typename TOffsets>
void
PrintImageNeighborhoodShape(const TOffsets & offsets)
{
std::cout << " ";

for (const OffsetType & offset : offsets)
{
std::cout << offset << ' ';
}

using ImageType = itk::Image<int>;
const auto image = ImageType::New();
constexpr unsigned int imageSize{ 7 };
image->SetRegions(ImageType::SizeType::Filled(imageSize));
image->Allocate(true);

const auto centerIndex = ImageType::IndexType::Filled(imageSize / 2);
const itk::ShapedImageNeighborhoodRange<ImageType> shapedImageNeighborhoodRange(*image, centerIndex, offsets);

// Set the values of the pixels in the "shaped neighborhood" of the image center to 1, 2, 3, ..., N, consecutively.
std::iota(shapedImageNeighborhoodRange.begin(), shapedImageNeighborhoodRange.end(), 1);

std::cout << "\n\n";
const std::ios_base::fmtflags flags(std::cout.flags());
std::cout << std::hex << std::uppercase;

const itk::ImageBufferRange<const ImageType> imageBufferRange(*image);
auto imageBufferIterator = imageBufferRange.cbegin();

for (int y{ 0 }; y < imageSize; ++y)
{
std::cout << " ";

for (int x{ 0 }; x < imageSize; ++x)
{
std::cout << *imageBufferIterator << ' ';
++imageBufferIterator;
}
std::cout << '\n';
}
std::cout.flags(flags);
std::cout << '\n';
}

} // namespace


int
main()
{
const std::array<OffsetType, 3> offsets = { { { { 0, -1 } }, { { 0, 1 } }, { { 1, 1 } } } };
std::cout << "Shape of some arbitrary offsets:\n\n";
PrintImageNeighborhoodShape(offsets);

const bool includeCenterPixel = false;
const size_t maximumCityblockDistance = 1;
std::cout << "4-connected neighborhood shape (excluding the center pixel) with maximumCityblockDistance = "
<< maximumCityblockDistance << ":\n\n";

// GenerateConnectedImageNeighborhoodShapeOffsets returns an std::array of offsets.
const auto connectedImageNeighborhoodShapeOffsets =
itk::GenerateConnectedImageNeighborhoodShapeOffsets<Dimension, maximumCityblockDistance, includeCenterPixel>();
PrintImageNeighborhoodShape(connectedImageNeighborhoodShapeOffsets);

const itk::Size<Dimension> radius = { { 1, 2 } };
std::cout << "Rectangular shape of radius " << radius << ":\n\n";

// GenerateRectangularImageNeighborhoodOffsets returns an std::vector of offsets.
const auto rectangularImageNeighborhoodOffsets = itk::GenerateRectangularImageNeighborhoodOffsets(radius);
PrintImageNeighborhoodShape(rectangularImageNeighborhoodOffsets);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
:name: GenerateOffsetsShapedImageNeighborhood

Generate the Offsets of a Shaped Image Neighborhood
===================================================

.. index::
single: ConnectedImageNeighborhoodShape
single: RectangularImageNeighborhoodShape
single: ShapedImageNeighborhoodRange


Synopsis
--------


This example demonstrates various ways to create a container of offsets, to
specify the shape of a neighborhood of pixels:

- An arbitrary shape
- A 4-connected neighborhood shape
- A rectangular neighborhood shape

These offsets may be used to specify the shape of a ShapedImageNeighborhoodRange
(as included with this code example), or a ShapedNeighborhoodIterator.

Results
-------

Output::

Shape of some arbitrary offsets:

[0, -1] [0, 1] [1, 1]

0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 0 0 0 0 0
0 0 0 2 3 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0

4-connected neighborhood shape (excluding the center pixel) with maximumCityblockDistance = 1:

[0, -1] [-1, 0] [1, 0] [0, 1]

0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 1 0 0 0
0 0 2 0 3 0 0
0 0 0 4 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0

Rectangular shape of radius [1, 2]:

[-1, -2] [0, -2] [1, -2] [-1, -1] [0, -1] [1, -1] [-1, 0] [0, 0] [1, 0] [-1, 1] [0, 1] [1, 1] [-1, 2] [0, 2] [1, 2]

0 0 0 0 0 0 0
0 0 1 2 3 0 0
0 0 4 5 6 0 0
0 0 7 8 9 0 0
0 0 A B C 0 0
0 0 D E F 0 0
0 0 0 0 0 0 0


Code
----

C++
...

.. literalinclude:: Code.cxx
:lines: 18-


Classes demonstrated
--------------------

.. breathelink:: itk::ConnectedImageNeighborhoodShape itk::RectangularImageNeighborhoodShape
1 change: 1 addition & 0 deletions src/Core/Common/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Common
FilterImageUsingMultipleThreads/Documentation.rst
FilterImageWithoutCopying/Documentation.rst
FindMaxAndMinInImage/Documentation.rst
GenerateOffsetsShapedImageNeighborhood/Documentation.rst
GetImageSize/Documentation.rst
GetNameOfClass/Documentation.rst
GetOrSetMemberVariableOfITKClass/Documentation.rst
Expand Down

1 comment on commit 06cc158

@github-actions
Copy link

Choose a reason for hiding this comment

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

Please sign in to comment.