From e0a9024cfeb2bdde1b5be076219329c0755dff00 Mon Sep 17 00:00:00 2001
From: Mathieu Deltorre <mathieu.deltorre@c-s.fr>
Date: Mon, 5 May 2008 11:52:45 +0000
Subject: [PATCH] *Integration test nSIFT insight journal

---
 ...aleInvariantFeatureImageFilterHistTest.cxx | 419 ++++++++++++++++
 ...leInvariantFeatureImageFilterRHistTest.cxx | 419 ++++++++++++++++
 ...tkScaleInvariantFeatureImageFilterTest.cxx | 446 ++++++++++++++++++
 3 files changed, 1284 insertions(+)
 create mode 100644 Testing/Utilities/itkScaleInvariantFeatureImageFilterHistTest.cxx
 create mode 100644 Testing/Utilities/itkScaleInvariantFeatureImageFilterRHistTest.cxx
 create mode 100644 Testing/Utilities/itkScaleInvariantFeatureImageFilterTest.cxx

diff --git a/Testing/Utilities/itkScaleInvariantFeatureImageFilterHistTest.cxx b/Testing/Utilities/itkScaleInvariantFeatureImageFilterHistTest.cxx
new file mode 100644
index 0000000000..f8ebb3addf
--- /dev/null
+++ b/Testing/Utilities/itkScaleInvariantFeatureImageFilterHistTest.cxx
@@ -0,0 +1,419 @@
+/*=========================================================================
+Program: ITK nSIFT Implemention - Command Line Wrapper
+Module: $RCSfile: testnD.cxx,v $
+Language: C++
+Date: $Date: 2007/11/25 15:51:48 $
+Version: $Revision: 1.0 $
+Copyright (c) 2005,2006,2007 Warren Cheung
+All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* The name of the Insight Consortium, nor the names of any consortium members,
+nor of any contributors, may be used to endorse or promote products derived
+from this software without specific prior written permission.
+* Modified source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+=========================================================================*/
+
+#define VERBOSE
+//#define DEBUG
+//#define DEBUG_VERBOSE
+
+//#define SIFT_FEATURE
+//#define REORIENT
+
+#define GENERATE_KEYS 
+//#define SUBSAMPLE
+#define CROP
+//#define DO_DOUBLE
+
+#include "itkScaleInvariantFeatureImageFilter.h"
+#include "itkImageSeriesReader.h"
+#include "itkNumericSeriesFileNames.h"
+#include "itkPointSetToImageFilter.h"
+#include "itkImageFileWriter.h"
+#include <getopt.h>
+
+int itk2DScaleInvariantFeatureImageFilterHist( int argc, char *argv[] )
+{
+  // Command Line Arguments
+  unsigned int ARG_IMG1=2;
+  unsigned int ARG_IMG2=3;
+
+  const unsigned int    Dimension = 2;
+  
+  // Default scale is 1.0
+  double test_scale = 1.0;
+  float test_rotate = 0.0;  // 0 degrees
+  double test_crop = 0.5;
+  //  float test_rotate = 0.0874;  // 5 degrees
+  //float test_rotate = 0.1748;  // 10 degrees
+  int series_start = 1;
+  int series_end = 9;
+  int series_inc = 1;
+
+  int mode = 'i';  /* defaults to comparing 2 images */;
+  int rotate_middle=0; /* defaults to rotating around the origin */
+  
+#define OPT_SCALE 'x'
+#define OPT_ROTATE 'r'
+#define OPT_DIM 'd'
+#define OPT_CROP 'c'
+#define OPT_SERIES_START 's'
+#define OPT_SERIES_END 'e'
+#define OPT_SERIES_INC 'i'
+
+  /* new Getopt code */
+  while(1) {
+    static struct option long_options[] =
+      {
+	/* These options set a flag.   */
+	{"synthetic", 0, &mode, 's'},
+	{"image", 0, &mode, 'i'},
+	{"rotate-mid", 0, &rotate_middle, 1},
+	/* These options don't set a flag.
+	   We distinguish them by their indices.  */
+	{"scale", required_argument, 0, OPT_SCALE},
+	{"rotate", required_argument, 0, OPT_ROTATE},
+	{"crop", required_argument, 0, OPT_CROP},
+	{"series-start", required_argument, 0, OPT_SERIES_START},
+	{"series-end", required_argument, 0, OPT_SERIES_END},
+	{"series-inc", required_argument, 0, OPT_SERIES_INC},
+	//	{"dimension", required_argument, 0, OPT_DIM},
+	{0, 0, 0, 0}
+      };    
+
+    int optindex;
+    int val = getopt_long(argc, argv, "", long_options, &optindex);
+
+    if (val == -1)
+      break;
+
+    switch(val) {
+    case OPT_SCALE:
+      test_scale = atof(optarg);
+      break;
+    case OPT_ROTATE:
+      if (atof(optarg) >= 0.0 && atof(optarg) <= 360.0)
+      test_rotate = atof(optarg) * PI * 2.0 / 360.0;
+      break;
+    case OPT_CROP:
+      if (atof(optarg) <= 1.0) {
+	test_crop = atof(optarg);
+      }
+      break;
+    case OPT_SERIES_START:
+      series_start = atoi(optarg);
+      break;
+    case OPT_SERIES_END:
+      series_end = atoi(optarg);
+      break;
+    case OPT_SERIES_INC:
+      series_inc = atoi(optarg);
+      break;
+      /*
+    case OPT_DIM:
+      Dimension = atoi(optarg);
+      break;
+      */
+    }
+  }
+
+  ARG_IMG1 = optind;
+  ARG_IMG2 = optind+1;
+  
+  typedef  float  PixelType;
+  typedef itk::Image< PixelType, Dimension >  FixedImageType;
+  typedef itk::ScaleInvariantFeatureImageFilter<FixedImageType, Dimension> SiftFilterType;
+  typedef itk::Image<unsigned char, Dimension> OutputImageType;
+  
+  typedef itk::ImageSource< FixedImageType > ImageSourceType;
+
+  ImageSourceType::Pointer fixedImageReader, fixedImageReader2;
+
+  typedef itk::PointSetToImageFilter<SiftFilterType::PointSetType, OutputImageType> PointSetFilterType;
+  
+  if( static_cast<unsigned int>(argc) <= ARG_IMG1 || (mode == 'i' && static_cast<unsigned int>(argc) <= ARG_IMG2))
+    {
+      std::cerr << "Incorrect number of parameters " << std::endl;
+      std::cerr << std::endl;
+      std::cerr << "siftkeys program ( ";
+      std::cerr << Dimension << "D ";      
+#ifdef SIFT_FEATURE
+      std::cerr << "sift-feature ";
+#else
+      std::cerr << "histogram-feature ";
+#endif
+#ifdef REORIENT
+      std::cerr << "reoriented ";
+#endif
+      std::cerr << ")" << std::endl;
+
+      std::cerr << "Usage: \n";
+      std::cerr  << argv[0] << " [options] ImageFile [ImageFile2]\n"; 
+      std::cerr << "This program takes an input image file(s) and generates scale invariant features." << std::endl;
+      std::cerr << std::endl;
+      std::cerr << "Image Processing Options (Choose ONE):" << std::endl;
+      std::cerr << "--image" << std::endl;
+      std::cerr << " compare ImageFile and ImageFile2" << std::endl;
+      std::cerr << "\nOR\n" << std::endl;
+      std::cerr << "--synthetic" << std::endl;
+      std::cerr << " compare ImageFile to synthetically generated version" << std::endl;
+      std::cerr << "Synthetic Image Options:" << std::endl;
+      std::cerr << "--rotate value" << std::endl;
+      std::cerr << "  rotate synthetic image on first axis by value degrees" << std::endl;
+      std::cerr << "--rotate-middle" << std::endl;
+      std::cerr << "  centre of rotation at the centre of image (defaults to origin)" << std::endl;
+      std::cerr << "--scale value" << std::endl;
+      std::cerr << "  scale all axes of synthetic image by value" << std::endl;
+      std::cerr << "--tmp directory" << std::endl;
+      std::cerr << "  temporary directory" << std::endl;
+      std::cerr << std::endl;
+      return 1;
+    }
+
+  std::cerr << "Dimension = " << Dimension << "\n";
+  std::cerr << "Test Scale = " << test_scale << "\n";
+  std::cerr << "Test Rotate = " << test_rotate << "\n";
+  std::cerr << "Image Crop Ratio (first 3D) = " << test_crop << "\n";
+  std::cerr << "Mode = " << (char) mode << "\n";
+  std::cerr << "ImageFile1 = " << argv[optind] << "\n";
+  if (Dimension == 4) {
+    std::cerr << "Image Series Start = " << series_start << "\n";
+    std::cerr << "Image Series End = " << series_end << "\n";
+    std::cerr << "Image Series Inc = " << series_inc << "\n";
+  }
+
+#ifdef SIFT_FEATURE
+  std::cerr << "SIFT Feature\n" << std::endl;
+#else
+  std::cerr << "Histogram Feature\n" << std::endl;
+#endif
+
+#ifdef REORIENT
+  std::cerr << "Reorientation enabled\n" << std::endl;  
+#endif
+
+  if (Dimension == 4) {
+    /* Assume fileseries reader */
+    typedef itk::ImageSeriesReader< FixedImageType  > FixedImageReaderType;
+    FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+
+    typedef itk::NumericSeriesFileNames NameGeneratorType;
+    NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
+    
+    nameGenerator->SetSeriesFormat( argv[ARG_IMG1] );
+    nameGenerator->SetStartIndex( series_start );
+    nameGenerator->SetEndIndex( series_end );
+    nameGenerator->SetIncrementIndex( series_inc );
+        
+    tmpImageReader->SetFileNames( nameGenerator->GetFileNames() );
+
+    fixedImageReader = tmpImageReader;
+  } else {
+    typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
+    FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+    tmpImageReader  = FixedImageReaderType::New();
+
+    tmpImageReader->SetFileName(  argv[ARG_IMG1] );
+    fixedImageReader=tmpImageReader;
+  }
+  fixedImageReader->Update();
+
+  typedef itk::ScalableAffineTransform< double, Dimension > ScaleType;
+#ifdef CROP
+  ScaleType::Pointer no_transform = ScaleType::New();
+  no_transform->SetIdentity();
+  
+  SiftFilterType::ResampleFilterType::Pointer cropper = SiftFilterType::ResampleFilterType::New();
+  cropper->SetInput(fixedImageReader->GetOutput());
+  FixedImageType::SizeType cropsize = 
+    fixedImageReader->GetOutput()->GetLargestPossibleRegion().GetSize();
+  for (unsigned int k = 0; k < Dimension; ++k) {
+    if (k < 4)
+      cropsize[k] = (int) (cropsize[k] * test_crop);
+  }
+  cropper->SetSize( cropsize );
+  cropper->SetOutputSpacing(fixedImageReader->GetOutput()->GetSpacing());
+  cropper->SetTransform(no_transform);
+  cropper->Update();
+  FixedImageType::Pointer fixedImage = cropper->GetOutput();
+#else
+  FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();  
+#endif
+
+  SiftFilterType::PointSetTypePointer keypoints1, keypoints2;
+  PointSetFilterType::Pointer pointSet1 = PointSetFilterType::New();
+  PointSetFilterType::Pointer pointSet2 = PointSetFilterType::New();
+
+  SiftFilterType siftFilter1, siftFilter2;
+  
+#ifdef DEBUG
+  siftFilter1.writeImage(fixedImage, "tmp0.png");
+  std::cout << std::endl << "Starting SIFT Feature Extraction...\n";
+#endif
+  
+  keypoints1 = siftFilter1.getSiftFeatures(fixedImage);
+  
+  pointSet1->SetInput(keypoints1);
+  pointSet1->SetOutsideValue(0);
+  pointSet1->SetInsideValue(255);
+  pointSet1->SetSize(fixedImageReader->GetOutput()->GetLargestPossibleRegion().GetSize());
+  
+  typedef itk::ImageFileWriter<OutputImageType> WriterType;
+  
+  WriterType::Pointer writer = WriterType::New();
+  writer->SetFileName("tmp0_keys.png");
+  writer->SetInput(pointSet1->GetOutput());
+  writer->Update();
+  
+  typedef itk::ScalableAffineTransform< double, Dimension > TestTransformType;
+  TestTransformType::Pointer inv_test_transform;
+  
+  // Synthetic test image
+  if (mode=='s') {
+    std::cerr << std::endl << "Synthetic image mode\n";  
+    TestTransformType::Pointer test_transform = TestTransformType::New();
+    
+    inv_test_transform = TestTransformType::New();
+           
+    TestTransformType::InputPointType translate_vector;
+            
+    test_transform->SetIdentity();
+    test_transform->Scale( 1.0 / test_scale);
+    if (rotate_middle) {
+      std::cerr << "Rotation centred at middle of image." << std::endl;    
+      /* Cycle through each dimension and shift by half*/
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = size[k]/2.0;
+      test_transform->SetCenter( translate_vector);
+    } else {
+      std::cerr << "Rotation centred at origin." << std::endl;    
+    }
+#if 0
+    if (rotate_middle) {
+      std::cerr << "Rotation centred at middle of image." << std::endl;    
+      /* Cycle through each dimension and shift by half*/
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = size[k]/2.0;
+      test_transform->Translate( translate_vector);
+    } else {
+      std::cerr << "Rotation centred at origin." << std::endl;    
+    }
+#endif 
+
+    test_transform->Rotate(0,1,test_rotate);
+
+#if 0
+    if (rotate_middle) {
+      /* Cycle through each dimension and shift back*/
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = -translate_vector[k];
+      test_transform->Translate( translate_vector);
+    }
+#endif
+    
+    test_transform->GetInverse(inv_test_transform);
+    
+    {
+      FixedImageType::Pointer scaledImage;
+      
+      SiftFilterType::ResampleFilterType::Pointer scaler = SiftFilterType::ResampleFilterType::New();
+      scaler->SetInput(fixedImage);
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	size[k] = (unsigned int) floor(size[k] * test_scale);
+      scaler->SetSize( size );
+      scaler->SetOutputSpacing(fixedImage->GetSpacing());
+      scaler->SetTransform(test_transform);
+      scaler->Update();
+      scaledImage = scaler->GetOutput();
+      
+#ifdef DEBUG
+      siftFilter2.writeImage(scaledImage, "tmp1.png");
+      std::cout << std::endl;
+#endif
+      keypoints2 = siftFilter2.getSiftFeatures(scaledImage);
+    }
+    
+    std::cerr << "Test Image Scale: " << test_scale << std::endl;
+    // std::cerr << "Test Translate: " << test_translate << std::endl;
+    std::cerr << "Test Image Rotate: " << test_rotate << std::endl;    
+  } else if (mode == 'i') {
+    std::cerr << std::endl << "Image Comparison mode\n";  
+    inv_test_transform = NULL;
+
+    if (Dimension == 4) {
+      typedef itk::ImageSeriesReader< FixedImageType  > FixedImageReaderType;
+      FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+      tmpImageReader  = FixedImageReaderType::New();
+
+      typedef itk::NumericSeriesFileNames NameGeneratorType;
+      NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
+      
+      nameGenerator->SetSeriesFormat( argv[ARG_IMG2] );
+      nameGenerator->SetStartIndex( series_start );
+      nameGenerator->SetEndIndex( series_end );
+      nameGenerator->SetIncrementIndex( series_inc );
+      
+      tmpImageReader->SetFileNames( nameGenerator->GetFileNames() );
+      fixedImageReader2 = tmpImageReader;
+    } else {      
+      typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
+      FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+      tmpImageReader  = FixedImageReaderType::New();
+
+      tmpImageReader->SetFileName(  argv[ARG_IMG2] );
+      fixedImageReader2 = tmpImageReader;
+    }
+    fixedImageReader2->Update();
+
+#ifdef CROP
+    SiftFilterType::ResampleFilterType::Pointer cropper2 = SiftFilterType::ResampleFilterType::New();
+    cropper2->SetInput(fixedImageReader2->GetOutput());
+    FixedImageType::SizeType cropsize2 = 
+      fixedImageReader2->GetOutput()->GetLargestPossibleRegion().GetSize();
+    for (unsigned int k = 0; k < Dimension; ++k) {
+      if (k < 4)
+	cropsize2[k] /= 2;
+    }
+    cropper2->SetSize( cropsize2 );
+    cropper2->SetOutputSpacing(fixedImageReader2->GetOutput()->GetSpacing());
+    cropper2->SetTransform(no_transform);
+    cropper2->Update();
+    FixedImageType::Pointer fixedImage2 = cropper2->GetOutput();
+#else
+    FixedImageType::Pointer fixedImage2 = fixedImageReader2->GetOutput();  
+#endif
+
+    keypoints2 = siftFilter2.getSiftFeatures(fixedImage2);
+  }
+  
+  std::cerr << std::endl << "Matching Keypoints\n";  
+  siftFilter2.MatchKeypointsPos(keypoints1, keypoints2, inv_test_transform);
+#ifdef GENERATE_KEYS
+  siftFilter2.MatchKeypointsFeatures(keypoints1, keypoints2, inv_test_transform);
+#endif
+  return 0;
+
+}
diff --git a/Testing/Utilities/itkScaleInvariantFeatureImageFilterRHistTest.cxx b/Testing/Utilities/itkScaleInvariantFeatureImageFilterRHistTest.cxx
new file mode 100644
index 0000000000..68d2e7b414
--- /dev/null
+++ b/Testing/Utilities/itkScaleInvariantFeatureImageFilterRHistTest.cxx
@@ -0,0 +1,419 @@
+/*=========================================================================
+Program: ITK nSIFT Implemention - Command Line Wrapper
+Module: $RCSfile: testnD.cxx,v $
+Language: C++
+Date: $Date: 2007/11/25 15:51:48 $
+Version: $Revision: 1.0 $
+Copyright (c) 2005,2006,2007 Warren Cheung
+All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* The name of the Insight Consortium, nor the names of any consortium members,
+nor of any contributors, may be used to endorse or promote products derived
+from this software without specific prior written permission.
+* Modified source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+=========================================================================*/
+
+#define VERBOSE
+//#define DEBUG
+//#define DEBUG_VERBOSE
+
+//#define SIFT_FEATURE
+#define REORIENT
+
+#define GENERATE_KEYS 
+//#define SUBSAMPLE
+#define CROP
+//#define DO_DOUBLE
+
+#include "itkScaleInvariantFeatureImageFilter.h"
+#include "itkImageSeriesReader.h"
+#include "itkNumericSeriesFileNames.h"
+#include "itkPointSetToImageFilter.h"
+#include "itkImageFileWriter.h"
+#include <getopt.h>
+
+int itk2DScaleInvariantFeatureImageFilterRHist( int argc, char *argv[] )
+{
+  // Command Line Arguments
+  unsigned int ARG_IMG1=2;
+  unsigned int ARG_IMG2=3;
+
+  const unsigned int    Dimension = 2;
+  
+  // Default scale is 1.0
+  double test_scale = 1.0;
+  float test_rotate = 0.0;  // 0 degrees
+  double test_crop = 0.5;
+  //  float test_rotate = 0.0874;  // 5 degrees
+  //float test_rotate = 0.1748;  // 10 degrees
+  int series_start = 1;
+  int series_end = 9;
+  int series_inc = 1;
+
+  int mode = 'i';  /* defaults to comparing 2 images */;
+  int rotate_middle=0; /* defaults to rotating around the origin */
+  
+#define OPT_SCALE 'x'
+#define OPT_ROTATE 'r'
+#define OPT_DIM 'd'
+#define OPT_CROP 'c'
+#define OPT_SERIES_START 's'
+#define OPT_SERIES_END 'e'
+#define OPT_SERIES_INC 'i'
+
+  /* new Getopt code */
+  while(1) {
+    static struct option long_options[] =
+      {
+	/* These options set a flag.   */
+	{"synthetic", 0, &mode, 's'},
+	{"image", 0, &mode, 'i'},
+	{"rotate-mid", 0, &rotate_middle, 1},
+	/* These options don't set a flag.
+	   We distinguish them by their indices.  */
+	{"scale", required_argument, 0, OPT_SCALE},
+	{"rotate", required_argument, 0, OPT_ROTATE},
+	{"crop", required_argument, 0, OPT_CROP},
+	{"series-start", required_argument, 0, OPT_SERIES_START},
+	{"series-end", required_argument, 0, OPT_SERIES_END},
+	{"series-inc", required_argument, 0, OPT_SERIES_INC},
+	//	{"dimension", required_argument, 0, OPT_DIM},
+	{0, 0, 0, 0}
+      };    
+
+    int optindex;
+    int val = getopt_long(argc, argv, "", long_options, &optindex);
+
+    if (val == -1)
+      break;
+
+    switch(val) {
+    case OPT_SCALE:
+      test_scale = atof(optarg);
+      break;
+    case OPT_ROTATE:
+      if (atof(optarg) >= 0.0 && atof(optarg) <= 360.0)
+      test_rotate = atof(optarg) * PI * 2.0 / 360.0;
+      break;
+    case OPT_CROP:
+      if (atof(optarg) <= 1.0) {
+	test_crop = atof(optarg);
+      }
+      break;
+    case OPT_SERIES_START:
+      series_start = atoi(optarg);
+      break;
+    case OPT_SERIES_END:
+      series_end = atoi(optarg);
+      break;
+    case OPT_SERIES_INC:
+      series_inc = atoi(optarg);
+      break;
+      /*
+    case OPT_DIM:
+      Dimension = atoi(optarg);
+      break;
+      */
+    }
+  }
+
+  ARG_IMG1 = optind;
+  ARG_IMG2 = optind+1;
+  
+  typedef  float  PixelType;
+  typedef itk::Image< PixelType, Dimension >  FixedImageType;
+  typedef itk::ScaleInvariantFeatureImageFilter<FixedImageType, Dimension> SiftFilterType;
+  typedef itk::Image<unsigned char, Dimension> OutputImageType;
+  
+  typedef itk::ImageSource< FixedImageType > ImageSourceType;
+
+  ImageSourceType::Pointer fixedImageReader, fixedImageReader2;
+
+  typedef itk::PointSetToImageFilter<SiftFilterType::PointSetType, OutputImageType> PointSetFilterType;
+  
+  if( static_cast<unsigned int>(argc) <= ARG_IMG1 || (mode == 'i' && static_cast<unsigned int>(argc) <= ARG_IMG2))
+    {
+      std::cerr << "Incorrect number of parameters " << std::endl;
+      std::cerr << std::endl;
+      std::cerr << "siftkeys program ( ";
+      std::cerr << Dimension << "D ";      
+#ifdef SIFT_FEATURE
+      std::cerr << "sift-feature ";
+#else
+      std::cerr << "histogram-feature ";
+#endif
+#ifdef REORIENT
+      std::cerr << "reoriented ";
+#endif
+      std::cerr << ")" << std::endl;
+
+      std::cerr << "Usage: \n";
+      std::cerr  << argv[0] << " [options] ImageFile [ImageFile2]\n"; 
+      std::cerr << "This program takes an input image file(s) and generates scale invariant features." << std::endl;
+      std::cerr << std::endl;
+      std::cerr << "Image Processing Options (Choose ONE):" << std::endl;
+      std::cerr << "--image" << std::endl;
+      std::cerr << " compare ImageFile and ImageFile2" << std::endl;
+      std::cerr << "\nOR\n" << std::endl;
+      std::cerr << "--synthetic" << std::endl;
+      std::cerr << " compare ImageFile to synthetically generated version" << std::endl;
+      std::cerr << "Synthetic Image Options:" << std::endl;
+      std::cerr << "--rotate value" << std::endl;
+      std::cerr << "  rotate synthetic image on first axis by value degrees" << std::endl;
+      std::cerr << "--rotate-middle" << std::endl;
+      std::cerr << "  centre of rotation at the centre of image (defaults to origin)" << std::endl;
+      std::cerr << "--scale value" << std::endl;
+      std::cerr << "  scale all axes of synthetic image by value" << std::endl;
+      std::cerr << "--tmp directory" << std::endl;
+      std::cerr << "  temporary directory" << std::endl;
+      std::cerr << std::endl;
+      return 1;
+    }
+
+  std::cerr << "Dimension = " << Dimension << "\n";
+  std::cerr << "Test Scale = " << test_scale << "\n";
+  std::cerr << "Test Rotate = " << test_rotate << "\n";
+  std::cerr << "Image Crop Ratio (first 3D) = " << test_crop << "\n";
+  std::cerr << "Mode = " << (char) mode << "\n";
+  std::cerr << "ImageFile1 = " << argv[optind] << "\n";
+  if (Dimension == 4) {
+    std::cerr << "Image Series Start = " << series_start << "\n";
+    std::cerr << "Image Series End = " << series_end << "\n";
+    std::cerr << "Image Series Inc = " << series_inc << "\n";
+  }
+
+#ifdef SIFT_FEATURE
+  std::cerr << "SIFT Feature\n" << std::endl;
+#else
+  std::cerr << "Histogram Feature\n" << std::endl;
+#endif
+
+#ifdef REORIENT
+  std::cerr << "Reorientation enabled\n" << std::endl;  
+#endif
+
+  if (Dimension == 4) {
+    /* Assume fileseries reader */
+    typedef itk::ImageSeriesReader< FixedImageType  > FixedImageReaderType;
+    FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+
+    typedef itk::NumericSeriesFileNames NameGeneratorType;
+    NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
+    
+    nameGenerator->SetSeriesFormat( argv[ARG_IMG1] );
+    nameGenerator->SetStartIndex( series_start );
+    nameGenerator->SetEndIndex( series_end );
+    nameGenerator->SetIncrementIndex( series_inc );
+        
+    tmpImageReader->SetFileNames( nameGenerator->GetFileNames() );
+
+    fixedImageReader = tmpImageReader;
+  } else {
+    typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
+    FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+    tmpImageReader  = FixedImageReaderType::New();
+
+    tmpImageReader->SetFileName(  argv[ARG_IMG1] );
+    fixedImageReader=tmpImageReader;
+  }
+  fixedImageReader->Update();
+
+  typedef itk::ScalableAffineTransform< double, Dimension > ScaleType;
+#ifdef CROP
+  ScaleType::Pointer no_transform = ScaleType::New();
+  no_transform->SetIdentity();
+  
+  SiftFilterType::ResampleFilterType::Pointer cropper = SiftFilterType::ResampleFilterType::New();
+  cropper->SetInput(fixedImageReader->GetOutput());
+  FixedImageType::SizeType cropsize = 
+    fixedImageReader->GetOutput()->GetLargestPossibleRegion().GetSize();
+  for (unsigned int k = 0; k < Dimension; ++k) {
+    if (k < 4)
+      cropsize[k] = (int) (cropsize[k] * test_crop);
+  }
+  cropper->SetSize( cropsize );
+  cropper->SetOutputSpacing(fixedImageReader->GetOutput()->GetSpacing());
+  cropper->SetTransform(no_transform);
+  cropper->Update();
+  FixedImageType::Pointer fixedImage = cropper->GetOutput();
+#else
+  FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();  
+#endif
+
+  SiftFilterType::PointSetTypePointer keypoints1, keypoints2;
+  PointSetFilterType::Pointer pointSet1 = PointSetFilterType::New();
+  PointSetFilterType::Pointer pointSet2 = PointSetFilterType::New();
+
+  SiftFilterType siftFilter1, siftFilter2;
+  
+#ifdef DEBUG
+  siftFilter1.writeImage(fixedImage, "tmp0.png");
+  std::cout << std::endl << "Starting SIFT Feature Extraction...\n";
+#endif
+  
+  keypoints1 = siftFilter1.getSiftFeatures(fixedImage);
+  
+  pointSet1->SetInput(keypoints1);
+  pointSet1->SetOutsideValue(0);
+  pointSet1->SetInsideValue(255);
+  pointSet1->SetSize(fixedImageReader->GetOutput()->GetLargestPossibleRegion().GetSize());
+  
+  typedef itk::ImageFileWriter<OutputImageType> WriterType;
+  
+  WriterType::Pointer writer = WriterType::New();
+  writer->SetFileName("tmp0_keys.png");
+  writer->SetInput(pointSet1->GetOutput());
+  writer->Update();
+  
+  typedef itk::ScalableAffineTransform< double, Dimension > TestTransformType;
+  TestTransformType::Pointer inv_test_transform;
+  
+  // Synthetic test image
+  if (mode=='s') {
+    std::cerr << std::endl << "Synthetic image mode\n";  
+    TestTransformType::Pointer test_transform = TestTransformType::New();
+    
+    inv_test_transform = TestTransformType::New();
+           
+    TestTransformType::InputPointType translate_vector;
+            
+    test_transform->SetIdentity();
+    test_transform->Scale( 1.0 / test_scale);
+    if (rotate_middle) {
+      std::cerr << "Rotation centred at middle of image." << std::endl;    
+      /* Cycle through each dimension and shift by half*/
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = size[k]/2.0;
+      test_transform->SetCenter( translate_vector);
+    } else {
+      std::cerr << "Rotation centred at origin." << std::endl;    
+    }
+#if 0
+    if (rotate_middle) {
+      std::cerr << "Rotation centred at middle of image." << std::endl;    
+      /* Cycle through each dimension and shift by half*/
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = size[k]/2.0;
+      test_transform->Translate( translate_vector);
+    } else {
+      std::cerr << "Rotation centred at origin." << std::endl;    
+    }
+#endif 
+
+    test_transform->Rotate(0,1,test_rotate);
+
+#if 0
+    if (rotate_middle) {
+      /* Cycle through each dimension and shift back*/
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = -translate_vector[k];
+      test_transform->Translate( translate_vector);
+    }
+#endif
+    
+    test_transform->GetInverse(inv_test_transform);
+    
+    {
+      FixedImageType::Pointer scaledImage;
+      
+      SiftFilterType::ResampleFilterType::Pointer scaler = SiftFilterType::ResampleFilterType::New();
+      scaler->SetInput(fixedImage);
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	size[k] = (unsigned int) floor(size[k] * test_scale);
+      scaler->SetSize( size );
+      scaler->SetOutputSpacing(fixedImage->GetSpacing());
+      scaler->SetTransform(test_transform);
+      scaler->Update();
+      scaledImage = scaler->GetOutput();
+      
+#ifdef DEBUG
+      siftFilter2.writeImage(scaledImage, "tmp1.png");
+      std::cout << std::endl;
+#endif
+      keypoints2 = siftFilter2.getSiftFeatures(scaledImage);
+    }
+    
+    std::cerr << "Test Image Scale: " << test_scale << std::endl;
+    // std::cerr << "Test Translate: " << test_translate << std::endl;
+    std::cerr << "Test Image Rotate: " << test_rotate << std::endl;    
+  } else if (mode == 'i') {
+    std::cerr << std::endl << "Image Comparison mode\n";  
+    inv_test_transform = NULL;
+
+    if (Dimension == 4) {
+      typedef itk::ImageSeriesReader< FixedImageType  > FixedImageReaderType;
+      FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+      tmpImageReader  = FixedImageReaderType::New();
+
+      typedef itk::NumericSeriesFileNames NameGeneratorType;
+      NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
+      
+      nameGenerator->SetSeriesFormat( argv[ARG_IMG2] );
+      nameGenerator->SetStartIndex( series_start );
+      nameGenerator->SetEndIndex( series_end );
+      nameGenerator->SetIncrementIndex( series_inc );
+      
+      tmpImageReader->SetFileNames( nameGenerator->GetFileNames() );
+      fixedImageReader2 = tmpImageReader;
+    } else {      
+      typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
+      FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+      tmpImageReader  = FixedImageReaderType::New();
+
+      tmpImageReader->SetFileName(  argv[ARG_IMG2] );
+      fixedImageReader2 = tmpImageReader;
+    }
+    fixedImageReader2->Update();
+
+#ifdef CROP
+    SiftFilterType::ResampleFilterType::Pointer cropper2 = SiftFilterType::ResampleFilterType::New();
+    cropper2->SetInput(fixedImageReader2->GetOutput());
+    FixedImageType::SizeType cropsize2 = 
+      fixedImageReader2->GetOutput()->GetLargestPossibleRegion().GetSize();
+    for (unsigned int k = 0; k < Dimension; ++k) {
+      if (k < 4)
+	cropsize2[k] /= 2;
+    }
+    cropper2->SetSize( cropsize2 );
+    cropper2->SetOutputSpacing(fixedImageReader2->GetOutput()->GetSpacing());
+    cropper2->SetTransform(no_transform);
+    cropper2->Update();
+    FixedImageType::Pointer fixedImage2 = cropper2->GetOutput();
+#else
+    FixedImageType::Pointer fixedImage2 = fixedImageReader2->GetOutput();  
+#endif
+
+    keypoints2 = siftFilter2.getSiftFeatures(fixedImage2);
+  }
+  
+  std::cerr << std::endl << "Matching Keypoints\n";  
+  siftFilter2.MatchKeypointsPos(keypoints1, keypoints2, inv_test_transform);
+#ifdef GENERATE_KEYS
+  siftFilter2.MatchKeypointsFeatures(keypoints1, keypoints2, inv_test_transform);
+#endif
+  return 0;
+
+}
diff --git a/Testing/Utilities/itkScaleInvariantFeatureImageFilterTest.cxx b/Testing/Utilities/itkScaleInvariantFeatureImageFilterTest.cxx
new file mode 100644
index 0000000000..f27af71500
--- /dev/null
+++ b/Testing/Utilities/itkScaleInvariantFeatureImageFilterTest.cxx
@@ -0,0 +1,446 @@
+/*=========================================================================
+Program: ITK nSIFT Implemention - Command Line Wrapper
+Module: $RCSfile: testnD.cxx,v $
+Language: C++
+Date: $Date: 2007/11/25 15:51:48 $
+Version: $Revision: 1.0 $
+Copyright (c) 2005,2006,2007 Warren Cheung
+All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+* Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+* The name of the Insight Consortium, nor the names of any consortium members,
+nor of any contributors, may be used to endorse or promote products derived
+from this software without specific prior written permission.
+* Modified source versions must be plainly marked as such, and must not be
+misrepresented as being the original software.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+=========================================================================*/
+
+#define VERBOSE
+#define DEBUG
+//#define DEBUG_VERBOSE
+
+#define SIFT_FEATURE
+//#define REORIENT
+
+#define GENERATE_KEYS 
+//#define SUBSAMPLE
+#define CROP
+//#define DO_DOUBLE
+
+#include "itkScaleInvariantFeatureImageFilter.h"
+#include "itkImageSeriesReader.h"
+#include "itkNumericSeriesFileNames.h"
+#include "itkPointSetToImageFilter.h"
+#include "itkImageFileWriter.h"
+#include <getopt.h>
+
+int itk2DScaleInvariantFeatureImageFilter( int argc, char *argv[] )
+{
+
+  // Command Line Arguments
+  unsigned int ARG_IMG1=2;
+  unsigned int ARG_IMG2=3;
+  unsigned int ARG_TMP=4;
+  
+  const unsigned int    Dimension = 2;
+  
+  // Default scale is 1.0
+  double test_scale = 1.0;
+  float test_rotate = 0.0;  // 0 degrees
+  double test_crop = 0.5;
+  //  float test_rotate = 0.0874;  // 5 degrees
+  //float test_rotate = 0.1748;  // 10 degrees
+  int series_start = 1;
+  int series_end = 9;
+  int series_inc = 1;
+
+  int mode = 'i';  /* defaults to comparing 2 images */;
+  int rotate_middle=0; /* defaults to rotating around the origin */
+  
+#define OPT_SCALE 'x'
+#define OPT_ROTATE 'r'
+#define OPT_DIM 'd'
+#define OPT_CROP 'c'
+#define OPT_SERIES_START 's'
+#define OPT_SERIES_END 'e'
+#define OPT_SERIES_INC 'i'
+
+  /* new Getopt code */
+  while(1) {
+    static struct option long_options[] =
+      {
+	/* These options set a flag.   */
+	{"synthetic", 0, &mode, 's'},
+	{"image", 0, &mode, 'i'},
+	{"rotate-mid", 0, &rotate_middle, 1},
+	/* These options don't set a flag.
+	   We distinguish them by their indices.  */
+	{"scale", required_argument, 0, OPT_SCALE},
+	{"rotate", required_argument, 0, OPT_ROTATE},
+	{"crop", required_argument, 0, OPT_CROP},
+	{"series-start", required_argument, 0, OPT_SERIES_START},
+	{"series-end", required_argument, 0, OPT_SERIES_END},
+	{"series-inc", required_argument, 0, OPT_SERIES_INC},
+	//	{"dimension", required_argument, 0, OPT_DIM},
+	{0, 0, 0, 0}
+      };    
+
+    int optindex;
+    int val = getopt_long(argc, argv, "", long_options, &optindex);
+
+    if (val == -1)
+      break;
+
+    switch(val) {
+    case OPT_SCALE:
+      test_scale = atof(optarg);
+      break;
+    case OPT_ROTATE:
+      if (atof(optarg) >= 0.0 && atof(optarg) <= 360.0)
+      test_rotate = atof(optarg) * PI * 2.0 / 360.0;
+      break;
+    case OPT_CROP:
+      if (atof(optarg) <= 1.0) {
+	test_crop = atof(optarg);
+      }
+      break;
+    case OPT_SERIES_START:
+      series_start = atoi(optarg);
+      break;
+    case OPT_SERIES_END:
+      series_end = atoi(optarg);
+      break;
+    case OPT_SERIES_INC:
+      series_inc = atoi(optarg);
+      break;
+      /*
+    case OPT_DIM:
+      Dimension = atoi(optarg);
+      break;
+      */
+    }
+  }
+
+  ARG_IMG1 = optind;
+  ARG_IMG2 = optind+1;
+  
+  if (mode == 'i')
+    {
+      ARG_TMP = optind+2;
+    }
+  else
+    {
+      ARG_TMP = optind+1;
+    }
+
+  typedef  float  PixelType;
+  typedef itk::Image< PixelType, Dimension >  FixedImageType;
+  typedef itk::ScaleInvariantFeatureImageFilter<FixedImageType, Dimension> SiftFilterType;
+  typedef itk::Image<unsigned char, Dimension> OutputImageType;
+  
+  typedef itk::ImageSource< FixedImageType > ImageSourceType;
+
+  ImageSourceType::Pointer fixedImageReader, fixedImageReader2;
+
+  typedef itk::PointSetToImageFilter
+    <SiftFilterType::PointSetType, OutputImageType> PointSetFilterType;
+  
+  if( static_cast<unsigned int>(argc) <= ARG_IMG1 || (mode == 'i' && static_cast<unsigned int>(argc) <= ARG_IMG2 ) )
+    {
+      std::cerr << "Incorrect number of parameters " << std::endl;
+      std::cerr << std::endl;
+      std::cerr << "siftkeys program ( ";
+      std::cerr << Dimension << "D ";      
+#ifdef SIFT_FEATURE
+      std::cerr << "sift-feature ";
+#else
+      std::cerr << "histogram-feature ";
+#endif
+#ifdef REORIENT
+      std::cerr << "reoriented ";
+#endif
+      std::cerr << ")" << std::endl;
+
+      std::cerr << "Usage: \n";
+      std::cerr  << argv[0] << " [options] ImageFile [ImageFile2] [Temporary]\n"; 
+      std::cerr << "This program takes an input image file(s) and generates scale invariant features." << std::endl;
+      std::cerr << std::endl;
+      std::cerr << "Image Processing Options (Choose ONE):" << std::endl;
+      std::cerr << "--image" << std::endl;
+      std::cerr << " compare ImageFile and ImageFile2" << std::endl;
+      std::cerr << "\nOR\n" << std::endl;
+      std::cerr << "--synthetic" << std::endl;
+      std::cerr << " compare ImageFile to synthetically generated version" << std::endl;
+      std::cerr << "Synthetic Image Options:" << std::endl;
+      std::cerr << "--rotate value" << std::endl;
+      std::cerr << "  rotate synthetic image on first axis by value degrees" << std::endl;
+      std::cerr << "--rotate-middle" << std::endl;
+      std::cerr << "  centre of rotation at the centre of image (defaults to origin)" << std::endl;
+      std::cerr << "--scale value" << std::endl;
+      std::cerr << "  scale all axes of synthetic image by value" << std::endl;
+      std::cerr << "--tmp directory" << std::endl;
+      std::cerr << "  temporary directory" << std::endl;
+      std::cerr << std::endl;
+      return 1;
+    }
+
+  std::cerr << "Dimension = " << Dimension << "\n";
+  std::cerr << "Test Scale = " << test_scale << "\n";
+  std::cerr << "Test Rotate = " << test_rotate << "\n";
+  std::cerr << "Image Crop Ratio (first 3D) = " << test_crop << "\n";
+  std::cerr << "Mode = " << (char) mode << "\n";
+  std::cerr << "ImageFile1 = " << argv[optind] << "\n";
+  std::cerr << "Temp directory = " << argv[ARG_TMP] << "\n";
+  if (Dimension == 4) {
+    std::cerr << "Image Series Start = " << series_start << "\n";
+    std::cerr << "Image Series End = " << series_end << "\n";
+    std::cerr << "Image Series Inc = " << series_inc << "\n";
+  }
+
+#ifdef SIFT_FEATURE
+  std::cerr << "SIFT Feature\n" << std::endl;
+#else
+  std::cerr << "Histogram Feature\n" << std::endl;
+#endif
+
+#ifdef REORIENT
+  std::cerr << "Reorientation enabled\n" << std::endl;  
+#endif
+
+  if (Dimension == 4) {
+    /* Assume fileseries reader */
+    typedef itk::ImageSeriesReader< FixedImageType  > FixedImageReaderType;
+    FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+
+    typedef itk::NumericSeriesFileNames NameGeneratorType;
+    NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
+    
+    nameGenerator->SetSeriesFormat( argv[ARG_IMG1] );
+    nameGenerator->SetStartIndex( series_start );
+    nameGenerator->SetEndIndex( series_end );
+    nameGenerator->SetIncrementIndex( series_inc );
+        
+    tmpImageReader->SetFileNames( nameGenerator->GetFileNames() );
+
+    fixedImageReader = tmpImageReader;
+  } else {
+    typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
+    FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+    tmpImageReader  = FixedImageReaderType::New();
+
+    tmpImageReader->SetFileName(  argv[ARG_IMG1] );
+    fixedImageReader=tmpImageReader;
+  }
+  fixedImageReader->Update();
+
+  typedef itk::ScalableAffineTransform< double, Dimension > ScaleType;
+#ifdef CROP
+  ScaleType::Pointer no_transform = ScaleType::New();
+  no_transform->SetIdentity();
+  
+  SiftFilterType::ResampleFilterType::Pointer cropper = SiftFilterType::ResampleFilterType::New();
+  cropper->SetInput(fixedImageReader->GetOutput());
+  FixedImageType::SizeType cropsize = 
+    fixedImageReader->GetOutput()->GetLargestPossibleRegion().GetSize();
+  for (unsigned int k = 0; k < Dimension; ++k) {
+    if (k < 4)
+      cropsize[k] = (int) (cropsize[k] * test_crop);
+  }
+  cropper->SetSize( cropsize );
+  cropper->SetOutputSpacing(fixedImageReader->GetOutput()->GetSpacing());
+  cropper->SetTransform(no_transform);
+  cropper->Update();
+  FixedImageType::Pointer fixedImage = cropper->GetOutput();
+#else
+  FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();  
+#endif
+
+  SiftFilterType::PointSetTypePointer keypoints1, keypoints2;
+  PointSetFilterType::Pointer pointSet1 = PointSetFilterType::New();
+  PointSetFilterType::Pointer pointSet2 = PointSetFilterType::New();
+
+  SiftFilterType siftFilter1, siftFilter2;
+  
+  if ( static_cast<unsigned int>(argc)-1 == ARG_TMP)
+    {
+      siftFilter1.SetTemporaryDir(argv[ARG_TMP]);
+    }
+
+#ifdef DEBUG
+  siftFilter1.writeImage(fixedImage, "utScaleInvariantFeatureImageFilter_0.png");
+  std::cout << std::endl << "Starting SIFT Feature Extraction...\n";
+#endif
+  
+  keypoints1 = siftFilter1.getSiftFeatures(fixedImage);
+  
+  pointSet1->SetInput(keypoints1);
+  pointSet1->SetOutsideValue(0);
+  pointSet1->SetInsideValue(255);
+  pointSet1->SetSize(fixedImage->GetLargestPossibleRegion().GetSize());
+  
+  typedef itk::ImageFileWriter<OutputImageType> WriterType;
+  
+  WriterType::Pointer writer = WriterType::New();
+  
+  std::string keys0_name = "";
+  if (static_cast<unsigned int>(argc)-1 == ARG_TMP)
+    {
+      keys0_name = argv[ARG_TMP];
+      keys0_name+="/";
+    }
+  keys0_name+="utScaleInvariantFeatureImageFilter_keys0.png";
+  writer->SetFileName(keys0_name.c_str());
+  writer->SetInput(pointSet1->GetOutput());
+  writer->Update();
+  //siftFilter1.writeImage(pointSet1->GetOutput(), "utScaleInvariantFeatureImageFilter_keys0.png");
+  
+  typedef itk::ScalableAffineTransform< double, Dimension > TestTransformType;
+  TestTransformType::Pointer inv_test_transform;
+  
+  // Synthetic test image
+  if (mode=='s') {
+    std::cerr << std::endl << "Synthetic image mode\n";  
+    TestTransformType::Pointer test_transform = TestTransformType::New();
+    
+    inv_test_transform = TestTransformType::New();
+           
+    TestTransformType::InputPointType translate_vector;
+            
+    test_transform->SetIdentity();
+    test_transform->Scale( 1.0 / test_scale);
+    if (rotate_middle) {
+      std::cerr << "Rotation centred at middle of image." << std::endl;    
+      /* Cycle through each dimension and shift by half*/
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = size[k]/2.0;
+      test_transform->SetCenter( translate_vector);
+    } else {
+      std::cerr << "Rotation centred at origin." << std::endl;    
+    }
+#if 0
+    if (rotate_middle) {
+      std::cerr << "Rotation centred at middle of image." << std::endl;    
+      /* Cycle through each dimension and shift by half*/
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = size[k]/2.0;
+      test_transform->Translate( translate_vector);
+    } else {
+      std::cerr << "Rotation centred at origin." << std::endl;    
+    }
+#endif 
+
+    test_transform->Rotate(0,1,test_rotate);
+
+#if 0
+    if (rotate_middle) {
+      /* Cycle through each dimension and shift back*/
+      for (unsigned int k = 0; k < Dimension; ++k)
+	translate_vector[k] = -translate_vector[k];
+      test_transform->Translate( translate_vector);
+    }
+#endif
+    
+    test_transform->GetInverse(inv_test_transform);
+    
+    {
+      FixedImageType::Pointer scaledImage;
+      
+      SiftFilterType::ResampleFilterType::Pointer scaler = SiftFilterType::ResampleFilterType::New();
+      scaler->SetInput(fixedImage);
+      FixedImageType::SizeType size = 
+	fixedImage->GetLargestPossibleRegion().GetSize();
+      for (unsigned int k = 0; k < Dimension; ++k)
+	size[k] = (unsigned int) floor(size[k] * test_scale);
+      scaler->SetSize( size );
+      scaler->SetOutputSpacing(fixedImage->GetSpacing());
+      scaler->SetTransform(test_transform);
+      scaler->Update();
+      scaledImage = scaler->GetOutput();
+
+#ifdef DEBUG
+      siftFilter2.writeImage(scaledImage, "utScaleInvariantFeatureImageFilter_1.png");
+      std::cout << std::endl;
+#endif
+      keypoints2 = siftFilter2.getSiftFeatures(scaledImage);
+    }
+    
+    std::cerr << "Test Image Scale: " << test_scale << std::endl;
+    // std::cerr << "Test Translate: " << test_translate << std::endl;
+    std::cerr << "Test Image Rotate: " << test_rotate << std::endl;    
+  } else if (mode == 'i') {
+    std::cerr << std::endl << "Image Comparison mode\n";  
+    inv_test_transform = NULL;
+
+    if (Dimension == 4) {
+      typedef itk::ImageSeriesReader< FixedImageType  > FixedImageReaderType;
+      FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+      tmpImageReader  = FixedImageReaderType::New();
+
+      typedef itk::NumericSeriesFileNames NameGeneratorType;
+      NameGeneratorType::Pointer nameGenerator = NameGeneratorType::New();
+      
+      nameGenerator->SetSeriesFormat( argv[ARG_IMG2] );
+      nameGenerator->SetStartIndex( series_start );
+      nameGenerator->SetEndIndex( series_end );
+      nameGenerator->SetIncrementIndex( series_inc );
+      
+      tmpImageReader->SetFileNames( nameGenerator->GetFileNames() );
+      fixedImageReader2 = tmpImageReader;
+    } else {      
+      typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;
+      FixedImageReaderType::Pointer tmpImageReader  = FixedImageReaderType::New();
+      tmpImageReader  = FixedImageReaderType::New();
+
+      tmpImageReader->SetFileName(  argv[ARG_IMG2] );
+      fixedImageReader2 = tmpImageReader;
+    }
+    fixedImageReader2->Update();
+
+#ifdef CROP
+    SiftFilterType::ResampleFilterType::Pointer cropper2 = SiftFilterType::ResampleFilterType::New();
+    cropper2->SetInput(fixedImageReader2->GetOutput());
+    FixedImageType::SizeType cropsize2 = 
+      fixedImageReader2->GetOutput()->GetLargestPossibleRegion().GetSize();
+    for (unsigned int k = 0; k < Dimension; ++k) {
+      if (k < 4)
+	cropsize2[k] /= 2;
+    }
+    cropper2->SetSize( cropsize2 );
+    cropper2->SetOutputSpacing(fixedImageReader2->GetOutput()->GetSpacing());
+    cropper2->SetTransform(no_transform);
+    cropper2->Update();
+    FixedImageType::Pointer fixedImage2 = cropper2->GetOutput();
+#else
+    FixedImageType::Pointer fixedImage2 = fixedImageReader2->GetOutput();  
+#endif
+
+    keypoints2 = siftFilter2.getSiftFeatures(fixedImage2);
+  }
+  
+  std::cerr << std::endl << "Matching Keypoints\n";  
+  siftFilter2.MatchKeypointsPos(keypoints1, keypoints2, inv_test_transform);
+#ifdef GENERATE_KEYS
+  siftFilter2.MatchKeypointsFeatures(keypoints1, keypoints2, inv_test_transform);
+#endif
+  return 0;
+
+}
-- 
GitLab