1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkDoubleThresholdImageFilter_h
19 #define itkDoubleThresholdImageFilter_h
20 
21 #include "itkImageToImageFilter.h"
22 
23 namespace itk
24 {
25 /** \class DoubleThresholdImageFilter
26  * \brief Binarize an input image using double thresholding.
27  *
28  * Double threshold addresses the difficulty in selecting a threshold
29  * that will select the objects of interest without selecting
30  * extraneous objects. Double threshold considers two threshold
31  * ranges: a narrow range and a wide range (where the wide range
32  * encompasses the narrow range). If the wide range was used for a
33  * traditional threshold (where values inside the range map to the
34  * foreground and values outside the range map to the background),
35  * many extraneous pixels may survive the threshold operation. If the
36  * narrow range was used for a traditional threshold, then too few
37  * pixels may survive the threshold.
38  *
39  * Double threshold uses the narrow threshold image as a marker image
40  * and the wide threshold image as a mask image in the geodesic
41  * dilation. Essentially, the marker image (narrow threshold) is
42  * dilated but constrained to lie within the mask image (wide
43  * threshold). Thus, only the objects of interest (those pixels that
44  * survived the narrow threshold) are extracted but the those objects
45  * appear in the final image as they would have if the wide threshold
46  * was used.
47  *
48  * \sa GrayscaleGeodesicDilateImageFilter
49  * \sa MorphologyImageFilter, GrayscaleDilateImageFilter, GrayscaleFunctionDilateImageFilter, BinaryDilateImageFilter
50  * \ingroup ImageEnhancement  MathematicalMorphologyImageFilters
51  * \ingroup ITKMathematicalMorphology
52  */
53 template< typename TInputImage, typename TOutputImage >
54 class ITK_TEMPLATE_EXPORT DoubleThresholdImageFilter:
55   public ImageToImageFilter< TInputImage, TOutputImage >
56 {
57 public:
58   ITK_DISALLOW_COPY_AND_ASSIGN(DoubleThresholdImageFilter);
59 
60   /** Standard class type aliases. */
61   using Self = DoubleThresholdImageFilter;
62   using Superclass = ImageToImageFilter< TInputImage, TOutputImage >;
63   using Pointer = SmartPointer< Self >;
64   using ConstPointer = SmartPointer< const Self >;
65 
66   /** Method for creation through the object factory. */
67   itkNewMacro(Self);
68 
69   /** Run-time type information (and related methods). */
70   itkTypeMacro(DoubleThresholdImageFilter, ImageToImageFilter);
71 
72   /** Types from the superclass */
73   using InputImagePointer = typename Superclass::InputImagePointer;
74   using InputImageType = typename Superclass::InputImageType;
75 
76   /** Pixel types. */
77   using InputPixelType = typename TInputImage::PixelType;
78   using OutputPixelType = typename TOutputImage::PixelType;
79 
80   /** Set the "outside" pixel value. The default value
81    * NumericTraits<OutputPixelType>::ZeroValue(). */
82   itkSetMacro(OutsideValue, OutputPixelType);
83 
84   /** Get the "outside" pixel value. */
85   itkGetConstMacro(OutsideValue, OutputPixelType);
86 
87   /** Set the "inside" pixel value. The default value
88    * NumericTraits<OutputPixelType>::max() */
89   itkSetMacro(InsideValue, OutputPixelType);
90 
91   /** Get the "inside" pixel value. */
92   itkGetConstMacro(InsideValue, OutputPixelType);
93 
94   /** Set the thresholds. Four thresholds should be specified.  The
95    * two lower thresholds default to
96    * NumericTraits<InputPixelType>::NonpositiveMin(). The two upper
97    * thresholds default NumericTraits<InputPixelType>::max.
98    * Threshold1 <= Threshold2 <= Threshold3 <= Threshold4. */
99   itkSetMacro(Threshold1, InputPixelType);
100   itkSetMacro(Threshold2, InputPixelType);
101   itkSetMacro(Threshold3, InputPixelType);
102   itkSetMacro(Threshold4, InputPixelType);
103 
104   /** Get the threshold values. */
105   itkGetConstMacro(Threshold1, InputPixelType);
106   itkGetConstMacro(Threshold2, InputPixelType);
107   itkGetConstMacro(Threshold3, InputPixelType);
108   itkGetConstMacro(Threshold4, InputPixelType);
109 
110   /**
111    * Set/Get whether the connected components are defined strictly by
112    * face connectivity or by face+edge+vertex connectivity.  Default is
113    * FullyConnectedOff.  For objects that are 1 pixel wide, use
114    * FullyConnectedOn.
115    */
116   itkSetMacro(FullyConnected, bool);
117   itkGetConstReferenceMacro(FullyConnected, bool);
118   itkBooleanMacro(FullyConnected);
119 
120 #ifdef ITK_USE_CONCEPT_CHECKING
121   // Begin concept checking
122   itkConceptMacro( OutputEqualityComparableCheck,
123                    ( Concept::EqualityComparable< OutputPixelType > ) );
124   itkConceptMacro( InputComparableCheck,
125                    ( Concept::Comparable< InputPixelType > ) );
126   itkConceptMacro( InputOStreamWritableCheck,
127                    ( Concept::OStreamWritable< InputPixelType > ) );
128   itkConceptMacro( OutputOStreamWritableCheck,
129                    ( Concept::OStreamWritable< OutputPixelType > ) );
130   // End concept checking
131 #endif
132 
133 protected:
134   DoubleThresholdImageFilter();
135   ~DoubleThresholdImageFilter() override = default;
136   void PrintSelf(std::ostream & os, Indent indent) const override;
137 
138   /** DoubleThresholdImageFilter needs all of the input. So it must
139    * provide an implementation of GenerateInputRequestedRegion() */
140   void GenerateInputRequestedRegion() override;
141 
142   /** DoubleThresholdImageFilter produces all of the output and must
143    * provide an implementation of EnlargeOutputRequestedRegion() */
144   void EnlargeOutputRequestedRegion( DataObject *itkNotUsed(output) ) override;
145 
146   /** Single threaded version of
147    * GenerateData(). DoubleThresholdImageFilter delegates its
148    * implementation to the GrayscaleGeodesicDilateImageFilter. */
149   void GenerateData() override;
150 
151 private:
152   InputPixelType m_Threshold1;
153   InputPixelType m_Threshold2;
154   InputPixelType m_Threshold3;
155   InputPixelType m_Threshold4;
156 
157   OutputPixelType m_InsideValue;
158   OutputPixelType m_OutsideValue;
159 
160   unsigned long m_NumberOfIterationsUsed{1};
161 
162   bool m_FullyConnected;
163 };
164 } // end namespace itk
165 
166 #ifndef ITK_MANUAL_INSTANTIATION
167 #include "itkDoubleThresholdImageFilter.hxx"
168 #endif
169 
170 #endif
171