/*========================================================================= * * 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. * *=========================================================================*/ #ifndef itkFlatStructuringElement_h #define itkFlatStructuringElement_h #include "itkNeighborhood.h" #include #include "itkVector.h" #include "itkImage.h" namespace itk { /** \class FlatStructuringElement * \brief A class to support a variety of flat structuring elements, * including versions created by decomposition of lines. * * FlatStructuringElement provides several static methods, which can * be used to create a structuring element with a particular shape, * size, etc. Currently, those methods enable the creation of the following * structuring elements: ball, box, cross, annulus, or polygon. * Polygons are available as fast approximations of balls using line * decompositions. Boxes also use line decompositions. * * "Flat" refers to binary as opposed to grayscale structuring elements. Flat * structuring elements can be used for both binary and grayscale images. * * A Neighborhood has an N-dimensional \em radius. The radius is defined * separately for each dimension as the number of pixels that the neighborhood * extends outward from the center pixel. For example, a 2D Neighborhood * object with a radius of 2x3 has sides of length 5x7. * However, in the case of balls and annuli, this definition is slightly * different from the parametric definition of those objects. * For example, an ellipse of radius 2x3 has a diameter of 4x6, not 5x7. * To have a diameter of 5x7, the radius would need to increase by 0.5 * in each dimension. * Thus, the "radius" of the neighborhood and the "radius" of the * object should be distinguished. * * To accomplish this, the "ball" and "annulus" structuring elements * have an optional flag called "radiusIsParametric" (off by default). * Setting this flag to true will use the parametric definition of the object * and will generate structuring elements with more accurate areas, * which can be especially important when morphological operations are * intended to remove or retain objects of particular sizes. * When the mode is turned off (default), the radius is the same, but the object * diameter is set to (radius*2)+1, which is the size of the neighborhood region. * Thus, the original ball and annulus structuring * elements have a systematic bias in the radius of +0.5 voxels in each dimension * relative to the parametric definition of the radius. * Thus, we recommend turning this mode on for more accurate structuring elements, * but this mode is turned off by default for backward compatibility. * * As an example, a 3D ball of radius 5 should have an area of 523. * With this mode turned on, the number of "on" pixels is 515 (error 1.6%), * but with it turned off, the area is 739 (error 41%). * For a 3D annulus of radius 5 and thickness 2, the area should be 410. * With this mode turned on, the area is 392 (error 4.5%), * but when turned off it is 560 (error 36%). * This same trend holds for balls and annuli of any radius or dimension. * For more detailed experiments with this mode, please refer to the results of the * test itkFlatStructuringElementTest.cxx or the wiki example. * * \ingroup ITKMathematicalMorphology * * \sphinx * \sphinxexample{Filtering/MathematicalMorphology/ErodeBinaryImageUsingFlatStruct,Erode Binary Image Using Flat * Structure Element} \endsphinx \sphinx * \sphinxexample{Filtering/MathematicalMorphology/GenerateStructureElementsWithAccurateArea,Generate Structuring * Elements With Accurate Area} \endsphinx */ template class ITK_TEMPLATE_EXPORT FlatStructuringElement : public Neighborhood { public: /** Standard class type aliases. */ using Self = FlatStructuringElement; using Superclass = Neighborhood; /** External support for pixel type. */ using typename Superclass::PixelType; /** Iterator type alias support Note the naming is intentional, i.e., * AllocatorType::iterator and AllocatorType::const_iterator, because the * allocator may be a vnl object or other type, which uses this form. */ using typename Superclass::Iterator; using typename Superclass::ConstIterator; /** Size and value type alias support */ using typename Superclass::SizeType; using typename Superclass::OffsetType; /** Radius type alias support */ using typename Superclass::RadiusType; /** External slice iterator type alias support */ using typename Superclass::SliceIteratorType; /** External support for dimensionality. */ static constexpr unsigned int NeighborhoodDimension = VDimension; using LType = Vector; using DecompType = std::vector; /** ImageType used in constructors */ using ImageType = typename itk::Image; /** Default destructor. */ ~FlatStructuringElement() override = default; /** Default constructor. */ FlatStructuringElement() { m_Decomposable = false; m_RadiusIsParametric = false; } /** Various constructors */ /** * Create a box structuring element. The structuring element is * is decomposable. */ static Self Box(RadiusType radius); /** Create a ball structuring element */ static Self Ball(RadiusType radius, bool radiusIsParametric = false); /** Create a cross structuring element */ static Self Cross(RadiusType radius); /** Create an annulus structuring element */ static Self Annulus(RadiusType radius, unsigned int thickness = 1, bool includeCenter = false, bool radiusIsParametric = false); /** * Create a polygon structuring element. The structuring element is * is decomposable. * lines is the number of elements in the decomposition */ static Self Polygon(RadiusType radius, unsigned int lines); /** * Returns whether the structuring element is decomposable or not. If the * structuring is decomposable, the set of lines associated with the * structuring may be used by an algorithm instead of the standard buffer. */ bool GetDecomposable() const { return m_Decomposable; } void SetDecomposable(bool v) { m_Decomposable = v; } /** Return the lines associated with the structuring element */ const DecompType & GetLines() const { return (m_Lines); } void AddLine(LType l) { m_Lines.push_back(l); } bool CheckParallel(LType NewVec) const; /** * Fill the buffer of the structuring element based on the lines * associated to the structuring element */ void ComputeBufferFromLines(); /** * The RadiusIsParametric mode ensures that the area of the foreground * corresponds to the radius that was specified. * This defaults to "off" for backward compatibility. */ bool GetRadiusIsParametric() const { return m_RadiusIsParametric; } void SetRadiusIsParametric(bool flag) { m_RadiusIsParametric = flag; } itkBooleanMacro(RadiusIsParametric); /** Create a FlatStructureElement from a bool * image. Image must be odd in all dimensions.*/ static Self FromImage(const ImageType * image); protected: void PrintSelf(std::ostream & os, Indent indent) const override; private: bool m_Decomposable{}; DecompType m_Lines{}; template struct StructuringElementFacet { Vector P1, P2, P3; }; using FacetType = StructuringElementFacet; template static void GeneratePolygon(TStructuringElement & res, TRadius radius, unsigned int lines); static void GeneratePolygon(itk::FlatStructuringElement<2> & res, itk::Size<2> radius, unsigned int lines); static void GeneratePolygon(itk::FlatStructuringElement<3> & res, itk::Size<3> radius, unsigned int lines); using LType2 = Vector; using LType3 = Vector; using FacetType3 = StructuringElementFacet<3>; bool m_RadiusIsParametric{}; /** Check for correct odd size image. * Return image size. Called in constructor FromImage.*/ static RadiusType CheckImageSize(const ImageType * image); }; } // namespace itk #ifndef ITK_MANUAL_INSTANTIATION # include "itkFlatStructuringElement.hxx" #endif #endif