1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
|
/*=========================================================================
*
* 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 itkBlockMatchingImageFilter_h
#define itkBlockMatchingImageFilter_h
#include "itkMeshToMeshFilter.h"
#include "itkImage.h"
#include "itkPointSet.h"
#include "itkVector.h"
#include "itkDefaultDynamicMeshTraits.h"
#include <memory> // For unique_ptr.
namespace itk
{
/** \class BlockMatchingImageFilter
* \brief Computes displacements of given points from a fixed image in a
* floating image.
*
* BlockMatchingImageFilter takes fixed and moving Images as well as
* PointSet of feature points as inputs. Physical coordinates of feature
* points are stored as point coordinates. Points of the input point set
* must have unique identifiers within range 0..N-1, where N is the number
* of points. Pixels (pointData) of input point set are not used.
* Additionally, by default, feature points are expected to lie at least
* (SearchRadius + BlockRadius) voxels from a boundary. This is usually
* achieved by using an appropriate mask during selection of feature points.
* If you are unsure whether feature points satisfy the above condition set
* CheckBoundary flag to true which turns on boundary checks.
* The default output(0) is a PointSet with displacements stored as vectors.
* Additional output(1) is a PointSet containing similarities. Similarities
* are needed to compute displacements and are always computed. The number
* of points in the output PointSet is equal to the number of points in the
* input PointSet.
*
* The filter is templated over fixed Image, moving Image, input PointSet,
* output displacements PointSet and output similarities PointSet.
*
* This filter is intended to be used in the process of Physics-Based
* Non-Rigid Registration. It computes displacement for selected points based
* on similarity [M. Bierling, Displacement estimation by hierarchical block
* matching, Proc. SPIE Vis. Comm. and Image Proc., vol. 1001, pp. 942-951,
* 1988.].
*
* \author Andriy Kot, Center for Real-Time Computing, Old Dominion University,
* Norfolk, VA
*
* \sa MaskFeaturePointSelectionFilter
*
* \ingroup ITKRegistrationCommon
*
* \sphinx
* \sphinxexample{Registration/Common/MatchFeaturePoints,Match Feature Points}
* \endsphinx
*/
template <
typename TFixedImage,
typename TMovingImage = TFixedImage,
typename TFeatures = PointSet<Matrix<SpacePrecisionType, TFixedImage::ImageDimension, TFixedImage::ImageDimension>,
TFixedImage::ImageDimension>,
class TDisplacements =
PointSet<Vector<typename TFeatures::PointType::ValueType, TFeatures::PointDimension>, TFeatures::PointDimension>,
class TSimilarities = PointSet<SpacePrecisionType, TDisplacements::PointDimension>>
class ITK_TEMPLATE_EXPORT BlockMatchingImageFilter : public MeshToMeshFilter<TFeatures, TDisplacements>
{
public:
ITK_DISALLOW_COPY_AND_MOVE(BlockMatchingImageFilter);
static constexpr unsigned int ImageDimension = TFixedImage::ImageDimension;
/** Not input specific type alias */
using ImageRegionType = ImageRegion<ImageDimension>;
using ImageSizeType = Size<ImageDimension>;
using ImageIndexType = Index<ImageDimension>;
/** Fixed image type alias. */
using FixedImageType = TFixedImage;
using FixedImageConstPointer = typename FixedImageType::ConstPointer;
using FixedImagePixelType = typename FixedImageType::PixelType;
/** Moving image type alias. */
using MovingImageType = TMovingImage;
using MovingImageConstPointer = typename MovingImageType::ConstPointer;
/** Feature points pointset type alias. */
using FeaturePointsType = TFeatures;
using FeaturePointsPointer = typename FeaturePointsType::Pointer;
using FeaturePointsConstPointer = typename FeaturePointsType::ConstPointer;
using FeaturePointsPhysicalCoordinates = typename FeaturePointsType::PointType;
/** Displacement vectors type alias. */
using DisplacementsType = TDisplacements;
using DisplacementsPointer = typename DisplacementsType::Pointer;
using DisplacementsConstPointer = typename DisplacementsType::ConstPointer;
using DisplacementsVector = typename DisplacementsType::PixelType;
/** Displacement similarities type alias. */
using SimilaritiesType = TSimilarities;
using SimilaritiesPointer = typename SimilaritiesType::Pointer;
using SimilaritiesConstPointer = typename SimilaritiesType::ConstPointer;
using SimilaritiesValue = typename SimilaritiesType::PixelType;
/** Standard class type aliases. */
using Superclass = MeshToMeshFilter<FeaturePointsType, DisplacementsType>;
using Self = BlockMatchingImageFilter;
using Pointer = SmartPointer<Self>;
using ConstPointer = SmartPointer<const Self>;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** \see LightObject::GetNameOfClass() */
itkOverrideGetNameOfClassMacro(BlockMatchingImageFilter);
/** set/get half size */
itkSetMacro(BlockRadius, ImageSizeType);
itkGetConstMacro(BlockRadius, ImageSizeType);
/** set/get half window */
itkSetMacro(SearchRadius, ImageSizeType);
itkGetConstMacro(SearchRadius, ImageSizeType);
/** set/get fixed image */
itkSetInputMacro(FixedImage, FixedImageType);
itkGetInputMacro(FixedImage, FixedImageType);
/** set/get floating image */
itkSetInputMacro(MovingImage, MovingImageType);
itkGetInputMacro(MovingImage, MovingImageType);
/** set/get point list */
itkSetInputMacro(FeaturePoints, FeaturePointsType);
itkGetInputMacro(FeaturePoints, FeaturePointsType);
inline DisplacementsType *
GetDisplacements()
{
return dynamic_cast<DisplacementsType *>(this->ProcessObject::GetOutput(0));
}
inline SimilaritiesType *
GetSimilarities()
{
return dynamic_cast<SimilaritiesType *>(this->ProcessObject::GetOutput(1));
}
protected:
/** MakeOutput is provided for handling multiple outputs */
using Superclass::MakeOutput;
DataObject::Pointer
MakeOutput(ProcessObject::DataObjectPointerArraySizeType idx) override;
/** We need to create our own GenerateOutputInformation because the
* default version from ProcessObject result in a dynamic_cast of the input
* pointer to the output pointer type in PointSet::CopyInformation. This does
* not work since they are different types. */
void
GenerateOutputInformation() override;
/** We cannot stream (see comments in GenerateOutputInformation). */
void
EnlargeOutputRequestedRegion(DataObject * output) override;
/** Generate temporary containers to be used by individual threads exclusively */
virtual void
BeforeThreadedGenerateData();
virtual void
ThreadedGenerateData(ThreadIdType threadId);
/** Compose pieces computed by each thread into a single output */
virtual void
AfterThreadedGenerateData();
/** Start multithreader here since MeshToMesh filter does not provide multithreaded support */
void
GenerateData() override;
BlockMatchingImageFilter();
~BlockMatchingImageFilter() override = default;
void
PrintSelf(std::ostream & os, Indent indent) const override;
/** Static function used as a "callback" by the MultiThreaderBase.
*
* The threading library will call this routine for each thread, which will delegate the control to
* DynamicThreadedGenerateData() after setting the correct region for the thread.
*/
static ITK_THREAD_RETURN_FUNCTION_CALL_CONVENTION
ThreaderCallback(void * arg);
/** Internal structure used for passing image data into the threading library
*/
struct ThreadStruct
{
Pointer Filter;
};
private:
// algorithm parameters
ImageSizeType m_BlockRadius{};
ImageSizeType m_SearchRadius{};
// temporary dynamic arrays for storing threads outputs
SizeValueType m_PointsCount{};
std::unique_ptr<DisplacementsVector[]> m_DisplacementsVectorsArray;
std::unique_ptr<SimilaritiesValue[]> m_SimilaritiesValuesArray;
};
} // end namespace itk
#ifndef ITK_MANUAL_INSTANTIATION
# include "itkBlockMatchingImageFilter.hxx"
#endif
#endif
|