---
 milena/sandbox/anthony/Makefile           |    2 +-
 milena/sandbox/anthony/opencv/Makefile    |    5 +-
 milena/sandbox/anthony/opencv/main.cpp    |   32 +-
 milena/sandbox/anthony/src/dog-space.hh   |  690 +++++++++++++++--------------
 milena/sandbox/anthony/src/main.cc        |   48 +-
 milena/sandbox/anthony/src/scale-space.hh |   21 +-
 6 files changed, 412 insertions(+), 386 deletions(-)
diff --git a/milena/sandbox/anthony/Makefile b/milena/sandbox/anthony/Makefile
index 44edf3b..edd3807 100644
--- a/milena/sandbox/anthony/Makefile
+++ b/milena/sandbox/anthony/Makefile
@@ -1,4 +1,4 @@
-CCACHE=
+CCACHE=ccache
 CC=g++
 CFLAGS=-Wall -Wextra
 CLIBS=-I../../
diff --git a/milena/sandbox/anthony/opencv/Makefile b/milena/sandbox/anthony/opencv/Makefile
index 8e438f0..d9a8be4 100644
--- a/milena/sandbox/anthony/opencv/Makefile
+++ b/milena/sandbox/anthony/opencv/Makefile
@@ -2,7 +2,7 @@ CCACHE=
 CXX=clang++
 SRC=main.cpp
 LIBS=-L/usr/local/include -lopencv_highgui -lopencv_core -lopencv_features2d -lopencv_nonfree -D_GNU_SOURCE
-OUTPUT=cv
+OUTPUT=a.out
 CLEAN=${OUTPUT} *.jpg
 
 all: cv
@@ -10,6 +10,9 @@ all: cv
 cv:
 	${CCACHE} ${CXX} -O3 ${LIBS} ${SRC} -o ${OUTPUT}
 
+pyramid:
+	${CCACHE} ${CXX} -O3 ${LIBS} pyramid.cpp -o ${OUTPUT}
+
 debug:
 	${CCACHE} ${CXX} -g -ggdb -O0 ${LIBS} ${SRC} -o ${OUTPUT}
 
diff --git a/milena/sandbox/anthony/opencv/main.cpp b/milena/sandbox/anthony/opencv/main.cpp
index 2de37c1..a7e5713 100644
--- a/milena/sandbox/anthony/opencv/main.cpp
+++ b/milena/sandbox/anthony/opencv/main.cpp
@@ -10,14 +10,30 @@
 // MAIN ENTRY POINT
 int main(int argc, char* argv[])
 {
-  const cv::Mat input = cv::imread("../images/keith.pbm");
-  cv::SiftFeatureDetector detector;
-  std::vector<cv::KeyPoint> keypoints;
-  detector.detect(input, keypoints);
-
-  cv::Mat output;
-  cv::drawKeypoints(input, keypoints, output);
-  cv::imwrite("sift.jpg", output);
+  const cv::Mat input1 = cv::imread("../images/keith.pbm");
+  const cv::Mat input2 = cv::imread("../images/tshirt.pgm");
+
+  {
+    cv::SiftFeatureDetector detector;
+    std::vector<cv::KeyPoint> keypoints;
+    detector.detect(input1, keypoints);
+    std::cout << keypoints.size() << std::endl;
+
+    cv::Mat output;
+    cv::drawKeypoints(input1, keypoints, output);
+    cv::imwrite("sift1.jpg", output);
+  }
+
+  {
+    cv::SiftFeatureDetector detector;
+    std::vector<cv::KeyPoint> keypoints;
+    detector.detect(input2, keypoints);
+    std::cout << keypoints.size() << std::endl;
+
+    cv::Mat output;
+    cv::drawKeypoints(input2, keypoints, output);
+    cv::imwrite("sift2.jpg", output);
+  }
 
   return 0;
 
diff --git a/milena/sandbox/anthony/src/dog-space.hh b/milena/sandbox/anthony/src/dog-space.hh
index da35820..9c4fee9 100644
--- a/milena/sandbox/anthony/src/dog-space.hh
+++ b/milena/sandbox/anthony/src/dog-space.hh
@@ -12,6 +12,7 @@
 #include <mln/core/alias/neighb2d.hh>
 #include <mln/literal/all.hh>
 #include <mln/value/int_s16.hh>
+#include <mln/value/int_u8.hh>
 
 #include "scale-space.hh"
 #include "keypoint.hh"
@@ -22,377 +23,384 @@ using namespace mln;
 template<typename I, typename S>
 class DoGSpace : protected ScaleSpace<S>
 {
-    public:
-        DoGSpace(ScaleSpace<I>* _ss)
+  public:
+    DoGSpace(ScaleSpace<I>* ss)
+      : ss_(ss)
+    { /* NOTHING */ }
+
+    ~DoGSpace()
+    {
+      ScaleSpace<S>::~ScaleSpace();
+    }
+
+    void build(void)
+    {
+      ScaleSpace<S>::o = ss_->octave_count();
+      ScaleSpace<S>::g = ss_->gradient_count() - 1;
+
+      typedef typename std::vector< std::vector<I> >::iterator PIT;
+      typedef typename std::vector<I>::iterator IIT;
+
+      std::vector< std::vector<I> > sspyramid = ss_->getPyramid();
+      S dog;
+
+      for (PIT pit = sspyramid.begin(); pit != sspyramid.end(); ++pit)
+      {
+        std::vector<S> octave;
+        for (IIT iit = pit->begin(); (iit + 1) != pit->end(); ++iit)
         {
-            ss = _ss;
-        }
+          initialize(dog, *iit);
+          mln_piter(I) p(iit->domain());
 
-        ~DoGSpace()
-        {
-            ScaleSpace<S>::~ScaleSpace();
-        }
+          for_all(p)
+          {
+            value::int_u8 up = (*iit)(p);
+            value::int_u8 down = (*(iit+1))(p);
 
-        void build(void)
+            dog(p) = static_cast<value::int_s16>(up) - static_cast<value::int_s16>(down);
+          }
+          octave.push_back(dog);
+        }
+        ScaleSpace<S>::pyramid.push_back(octave);
+      }
+    }
+
+    void findKeypoints(std::list<Keypoint>& keypoints)
+    {
+      typedef typename std::vector< std::vector<S> >::iterator PIT;
+      typedef typename std::vector<S>::iterator IIT;
+
+      unsigned octave = 0;
+      for (PIT pit = ScaleSpace<S>::pyramid.begin(); pit != ScaleSpace<S>::pyramid.end(); ++pit)
+      {
+        unsigned gradient = 1;
+        for (IIT iit = pit->begin() + 1; (iit + 1) != pit->end(); ++iit)
         {
-            ScaleSpace<S>::o = ss->octave_count();
-            ScaleSpace<S>::g = ss->gradient_count() - 1;
+          S upper = *(iit-1);
+          S current = *iit;
+          S lower = *(iit+1);
 
-            typedef typename std::vector< std::vector<I> >::iterator PIT;
-            typedef typename std::vector<I>::iterator IIT;
+          mln_piter(I) p(current.domain());
 
-            std::vector< std::vector<I> > sspyramid = ss->getPyramid();
-            S dog;
+          for_all(p)
+          {
+            value::int_s16 center = current(p);
+            value::int_s16 min = 255;
+            value::int_s16 max = -256;
+            mln_niter(neighb2d) n(c8(), p);
 
-            for (PIT pit = sspyramid.begin(); pit != sspyramid.end(); ++pit)
+            int extrema = isExtrema(current, center, n);
+
+            if (extrema == -1) // Is a minimum
             {
-                std::vector<S> octave;
-                for (IIT iit = pit->begin(); (iit + 1) != pit->end(); ++iit)
-                {
-                    initialize(dog, *iit);
-                    mln_piter(I) p(iit->domain());
-
-                    for_all(p)
-                    {
-                        value::int_s16 up = (value::int_s16) (*iit)(p);
-                        value::int_s16 down = (value::int_s16) (*(iit+1))(p);
-                        value::int_s16 diff = down - up;
-                        //value::int_s16 diff = ( (int) (*iit)(p) ) - ( (int) ((*(iit+1))(p)) );
-
-                        //std::cout << up << " - " << down << " = " << diff << std::endl;
-
-                        dog(p) = diff;
-                    }
-                    octave.push_back(dog);
-                }
-                ScaleSpace<S>::pyramid.push_back(octave);
+              findMin(min, lower, upper, p, n);
+              if (center < min)
+                keypoints.push_back(Keypoint(p.col(), p.row(), octave, gradient, false));
             }
-        }
-
-        void findKeypoints(std::list<Keypoint>& keypoints)
-        {
-            typedef typename std::vector< std::vector<S> >::iterator PIT;
-            typedef typename std::vector<S>::iterator IIT;
-
-            unsigned octave = 0;
-            for (PIT pit = ScaleSpace<S>::pyramid.begin(); pit != ScaleSpace<S>::pyramid.end(); ++pit)
+            else if (extrema == 1) // Is a maximum
             {
-                unsigned gradient = 1;
-                for (IIT iit = pit->begin() + 1; (iit + 1) != pit->end(); ++iit)
-                {
-                    S upper = *(iit-1);
-                    S current = *iit;
-                    S lower = *(iit+1);
-
-                    mln_piter(I) p(current.domain());
-
-                    for_all(p)
-                    {
-                        value::int_s16 center = current(p);
-                        value::int_s16 min = 255;
-                        value::int_s16 max = -256;
-                        mln_niter(neighb2d) n(c8(), p);
-
-                        int extrema = isExtrema(current, center, n);
-
-                        if (extrema == -1) // Is a minimum
-                        {
-                            findMin(min, lower, upper, p, n);
-                            if (center < min)
-                                keypoints.push_back(Keypoint(p.col(), p.row(), octave, gradient, false));
-                        }
-                        else if (extrema == 1) // Is a maximum
-                        {
-                            findMax(max, lower, upper, p, n);
-                            if (center > max)
-                                keypoints.push_back(Keypoint(p.col(), p.row(), octave, gradient, true));
-                        }
-                    }
-
-                    ++gradient;
-                }
-
-                ++octave;
+              findMax(max, lower, upper, p, n);
+              if (center > max)
+                keypoints.push_back(Keypoint(p.col(), p.row(), octave, gradient, true));
             }
+          }
+
+          ++gradient;
         }
 
-        void discardLowContrastKeypoints(std::list<Keypoint>& keypoints)
+        ++octave;
+      }
+    }
+
+    void discardLowContrastKeypoints(std::list<Keypoint>& keypoints)
+    {
+      const static unsigned max_interpolation_depth = 5;
+      unsigned count = 0;
+      bool enough = false;
+      std::list<Keypoint>::iterator k = keypoints.begin();
+      std::list<Keypoint>::iterator end = keypoints.end();
+      Matrix* offset = NULL;
+      Matrix* previous_offset = NULL;
+
+      while (k != end)
+      {
+        while (!enough && count < max_interpolation_depth)
         {
-            const static unsigned max_interpolation_depth = 5;
-            unsigned count = 0;
-            bool enough = false;
-            std::list<Keypoint>::iterator k = keypoints.begin();
-            Matrix* offset = NULL;
-            Matrix* previous_offset = NULL;
-
-            while (k != keypoints.end())
+          unsigned octave = k->getOctave();
+          unsigned gradient = k->getGradient();
+          S dog = ScaleSpace<S>::pyramid[octave][gradient];
+          S dog_up = ScaleSpace<S>::pyramid[octave][gradient + 1];
+          S dog_down = ScaleSpace<S>::pyramid[octave][gradient - 1];
+          int col = k->getX();
+          int row = k->getY();
+
+          if (row < 0 || col < 0
+              || static_cast<unsigned>(row) >= dog.nrows()
+              || static_cast<unsigned>(col) >= dog.ncols())
+          {
+            count = max_interpolation_depth;
+            break;
+          }
+
+          /* Set the neighbors of the current level:
+           *  n5  n1  n6
+           *  n2  p   n3
+           *  n7  n4  n8
+           */
+          float p = dog(mln_psite(S)(row, col));
+
+          float n1 = dog(mln_psite(S)(row - 1, col));
+          float n2 = dog(mln_psite(S)(row, col - 1));
+          float n3 = dog(mln_psite(S)(row, col + 1));
+          float n4 = dog(mln_psite(S)(row + 1, col));
+
+          float n5 = dog(mln_psite(S)(row - 1, col - 1));
+          float n6 = dog(mln_psite(S)(row - 1, col + 1));
+          float n7 = dog(mln_psite(S)(row + 1, col - 1));
+          float n8 = dog(mln_psite(S)(row + 1, col + 1));
+
+          /* Set the neighbors of the upper level:
+           *      u1
+           *  u2  u   u3
+           *      u4
+           */
+          float u = dog_up(mln_psite(S)(row, col));
+          float u1 = dog_up(mln_psite(S)(row - 1, col));
+          float u2 = dog_up(mln_psite(S)(row, col - 1));
+          float u3 = dog_up(mln_psite(S)(row, col + 1));
+          float u4 = dog_up(mln_psite(S)(row + 1, col));
+
+          /* Set the neighbors of the lower level:
+           *      l1
+           *  l2  l   l3
+           *      l4
+           */
+          float l = dog_down(mln_psite(S)(row, col));
+          float l1 = dog_down(mln_psite(S)(row - 1, col));
+          float l2 = dog_down(mln_psite(S)(row, col - 1));
+          float l3 = dog_down(mln_psite(S)(row, col + 1));
+          float l4 = dog_down(mln_psite(S)(row + 1, col));
+
+          // Compute the offset
+
+          float dxx = n3 - 2.0 * p + n2;
+          float dyy = n4 - 2.0 * p + n1;
+          float dss = u - 2.0 * p + l;
+
+          float dxy = (n8 - n6 - n7 + n5) / 4.0;
+          float dxs = (u3 - u2 - l3 + l2) / 4.0;
+          float dys = (u4 - u1 - l4 + l1) / 4.0;
+
+          Matrix m1(3, 1);
+          m1.initialize();
+          m1.set(0, 0, n3 - n2);
+          m1.set(1, 0, n4 - n1);
+          m1.set(2, 0, u - l);
+
+          Matrix m2(3, 3);
+          m2.initialize();
+          m2.set(0, 0, dxx);  m2.set(0, 1, dxy);  m2.set(0, 2, dxs);
+          m2.set(1, 0, dxy);  m2.set(1, 1, dyy);  m2.set(1, 2, dys);
+          m2.set(2, 0, dxs);  m2.set(2, 1, dys);  m2.set(2, 2, dss);
+
+          previous_offset = offset;
+          offset = m2.solve3x3(m1);
+
+          if (offset == NULL)
+          {
+            offset = previous_offset;
+            enough = true;
+          }
+          else
+          {
+            if (std::abs(offset->get(0,0)) > 0.5 ||
+                std::abs(offset->get(1,0)) > 0.5 ||
+                std::abs(offset->get(2,0)) > 0.5)
             {
-                while (!enough && count < max_interpolation_depth)
-                {
-                    std::cout << "test1" << std::endl;
-                    unsigned octave = k->getOctave();
-                    unsigned gradient = k->getGradient();
-                    S dog = ScaleSpace<S>::pyramid[octave][gradient];
-                    S dog_up = ScaleSpace<S>::pyramid[octave][gradient + 1];
-                    S dog_down = ScaleSpace<S>::pyramid[octave][gradient - 1];
-                    unsigned col = k->getX();
-                    unsigned row = k->getY();
-                    std::cout << "test2" << std::endl;
-
-                    /* Set the neighbors of the current level:
-                     *  n5  n1  n6
-                     *  n2  p   n3
-                     *  n7  n4  n8
-                     */
-                    float p = dog(mln_psite(S)(row, col));
-
-                    float n1 = dog(mln_psite(S)(row - 1, col));
-                    float n2 = dog(mln_psite(S)(row, col - 1));
-                    float n3 = dog(mln_psite(S)(row, col + 1));
-                    float n4 = dog(mln_psite(S)(row + 1, col));
-
-                    float n5 = dog(mln_psite(S)(row - 1, col - 1));
-                    float n6 = dog(mln_psite(S)(row - 1, col + 1));
-                    float n7 = dog(mln_psite(S)(row + 1, col - 1));
-                    float n8 = dog(mln_psite(S)(row + 1, col + 1));
-
-                    /* Set the neighbors of the upper level:
-                     *      u1
-                     *  u2  u   u3
-                     *      u4
-                     */
-                    float u = dog_up(mln_psite(S)(row, col));
-                    float u1 = dog_up(mln_psite(S)(row - 1, col));
-                    float u2 = dog_up(mln_psite(S)(row, col - 1));
-                    float u3 = dog_up(mln_psite(S)(row, col + 1));
-                    float u4 = dog_up(mln_psite(S)(row + 1, col));
-
-                    /* Set the neighbors of the lower level:
-                     *      l1
-                     *  l2  l   l3
-                     *      l4
-                     */
-                    float l = dog_down(mln_psite(S)(row, col));
-                    float l1 = dog_down(mln_psite(S)(row - 1, col));
-                    float l2 = dog_down(mln_psite(S)(row, col - 1));
-                    float l3 = dog_down(mln_psite(S)(row, col + 1));
-                    float l4 = dog_down(mln_psite(S)(row + 1, col));
-
-                    // Compute the offset
-
-                    float dxx = n3 - 2.0 * p + n2;
-                    float dyy = n4 - 2.0 * p + n1;
-                    float dss = u - 2.0 * p + l;
-
-                    float dxy = (n8 - n6 - n7 + n5) / 4.0;
-                    float dxs = (u3 - u2 - l3 + l2) / 4.0;
-                    float dys = (u4 - u1 - l4 + l1) / 4.0;
-
-                    std::cout << "test3" << std::endl;
-                    Matrix m1(3, 1);
-                    m1.initialize();
-                    m1.set(0, 0, n3 - n2);
-                    m1.set(1, 0, n4 - n1);
-                    m1.set(2, 0, u - l);
-
-                    Matrix m2(3, 3);
-                    m2.initialize();
-                    m2.set(0, 0, dxx);  m2.set(0, 1, dxy);  m2.set(0, 2, dxs);
-                    m2.set(1, 0, dxy);  m2.set(1, 1, dyy);  m2.set(1, 2, dys);
-                    m2.set(2, 0, dxs);  m2.set(2, 1, dys);  m2.set(2, 2, dss);
-
-                    std::cout << "test4" << std::endl;
-                    previous_offset = offset;
-                    offset = m2.solve3x3(m1);
-                    std::cout << "test5" << std::endl;
-
-                    if (offset == NULL)
-                    {
-                        offset = previous_offset;
-                        enough = true;
-                    }
-                    else
-                    {
-                        if (std::abs(offset->get(0,0)) > 0.5 ||
-                                std::abs(offset->get(1,0)) > 0.5 ||
-                                std::abs(offset->get(2,0)) > 0.5)
-                        {
-                            std::cout << "test51" << std::endl;
-                            ++count;
-                            k->setX(k->getX() + (int) offset->get(0, 0));
-                            k->setY(k->getX() + (int) offset->get(1, 0));
-                            k->setGradient(k->getGradient() + (int) offset->get(1, 0));
-
-                            //FIXME Check boundaries
-
-                            if (k->getGradient() < 1 ||
-                                    k->getGradient() >= ScaleSpace<S>::pyramid[0].size() - 1)
-                                count = max_interpolation_depth; // Remove keypoint
-                        }
-                        else
-                        {
-                            std::cout << "test52" << std::endl;
-                            enough = true;
-                        }
-                    }
-                }
-
-                std::cout << "test6" << std::endl;
-                if (count >= max_interpolation_depth)
-                {
-                    std::cout << "test61" << std::endl;
-                    k = keypoints.erase(k);
-                }
-                else
-                {
-                    std::cout << "test62" << std::endl;
-                    unsigned octave = k->getOctave();
-                    unsigned gradient = k->getGradient();
-
-                    S dog = ScaleSpace<S>::pyramid[octave][gradient];
-                    S dog_up = ScaleSpace<S>::pyramid[octave][gradient + 1];
-                    S dog_down = ScaleSpace<S>::pyramid[octave][gradient - 1];
-                    unsigned col = k->getX();
-                    unsigned row = k->getY();
-
-                    /* Set the neighbors of the current level:
-                     *      n1
-                     *  n2  p   n3
-                     *      n4
-                     */
-                    float p = dog(mln_psite(S)(row, col));
-
-                    float n1 = dog(mln_psite(S)(row - 1, col));
-                    float n2 = dog(mln_psite(S)(row, col - 1));
-                    float n3 = dog(mln_psite(S)(row, col + 1));
-                    float n4 = dog(mln_psite(S)(row + 1, col));
-
-                    // Set the neighbors of the upper/lower level:
-                    float u = dog_up(mln_psite(S)(row, col));
-                    float l = dog_down(mln_psite(S)(row, col));
-
-                    Matrix firstOrder(3, 1);
-                    firstOrder.initialize();
-
-                    /************ WARNING ************/
-                    /*       Maybe missing /255      */
-                    /*********************************/
-
-                    firstOrder.set(0, 0, n3 - n2);
-                    firstOrder.set(1, 0, n4 - n1);
-                    firstOrder.set(2, 0, u - l);
-
-                    float product = firstOrder.dotProduct(offset);
-                    float contrast = p + product / 2.0;
-
-                    if (contrast < 0.03)
-                        k = keypoints.erase(k);
-                    else
-                        k++;
-                }
-
-                enough = false;
-                count = 0;
-            }
-        }
+              ++count;
+              k->setX(k->getX() + (int) offset->get(0, 0));
+              k->setY(k->getX() + (int) offset->get(1, 0));
+              k->setGradient(k->getGradient() + (int) offset->get(1, 0));
 
-        void eliminateEdgeResponses(std::list<Keypoint>& keypoints)
-        {
-            const static float bound_ratio = 12.1;
+              //FIXME Check boundaries
 
-            for (std::list<Keypoint>::iterator k = keypoints.begin();
-                    k != keypoints.end(); ++k)
+              if (k->getGradient() < 1 ||
+                  k->getGradient() >= ScaleSpace<S>::pyramid[0].size() - 1)
+                count = max_interpolation_depth; // Remove keypoint
+            }
+            else
             {
-                unsigned octave = k->getOctave();
-                unsigned gradient = k->getGradient();
-                S dog = ScaleSpace<S>::pyramid[octave][gradient];
-                unsigned col = k->getX();
-                unsigned row = k->getY();
-
-                /* Set the neighbors:
-                 *  n5  n1  n6
-                 *  n2  p   n3
-                 *  n7  n4  n8
-                 */
-                float p = dog(mln_psite(S)(row, col));
-
-                float n1 = dog(mln_psite(S)(row - 1, col));
-                float n2 = dog(mln_psite(S)(row, col - 1));
-                float n3 = dog(mln_psite(S)(row, col + 1));
-                float n4 = dog(mln_psite(S)(row + 1, col));
-
-                float n5 = dog(mln_psite(S)(row - 1, col - 1));
-                float n6 = dog(mln_psite(S)(row - 1, col + 1));
-                float n7 = dog(mln_psite(S)(row + 1, col - 1));
-                float n8 = dog(mln_psite(S)(row + 1, col + 1));
-
-                // Set Hessian matrix and find the ratio
-
-                float dxx = n3 - 2.0 * p + n2;
-                float dyy = n4 - 2.0 * p + n1;
-                float dxy = (n8 - n6 - n7 + n5) / 4.0;
-
-                float trace = dxx + dyy;
-                float determinant = dxx * dyy - dxy * dxy;
-                float ratio = (trace * trace) / determinant;
-
-                if (determinant <= 0 || ratio >= bound_ratio)
-                    keypoints.erase(k);
+              enough = true;
             }
+          }
         }
 
-        virtual void save()
+        if (count >= max_interpolation_depth)
         {
+          k = keypoints.erase(k);
         }
-
-    private:
-        ScaleSpace<I>* ss;
-
-        int isExtrema(S& current, value::int_s16& center,
-                typename neighb2d::fwd_niter n)
+        else
         {
-            bool min = true;
-            bool max = true;
-
-            for_all(n)
-            {
-                min = (min && center < current(n));
-                max = (max && center > current(n));
-            }
-
-            if (min)
-                return -1;
-            else if (max)
-                return 1;
-            else
-                return 0;
+          unsigned octave = k->getOctave();
+          unsigned gradient = k->getGradient();
+
+          S dog = ScaleSpace<S>::pyramid[octave][gradient];
+          S dog_up = ScaleSpace<S>::pyramid[octave][gradient + 1];
+          S dog_down = ScaleSpace<S>::pyramid[octave][gradient - 1];
+          unsigned col = k->getX();
+          unsigned row = k->getY();
+
+          /* Set the neighbors of the current level:
+           *      n1
+           *  n2  p   n3
+           *      n4
+           */
+          float p = dog(mln_psite(S)(row, col));
+
+          float n1 = dog(mln_psite(S)(row - 1, col));
+          float n2 = dog(mln_psite(S)(row, col - 1));
+          float n3 = dog(mln_psite(S)(row, col + 1));
+          float n4 = dog(mln_psite(S)(row + 1, col));
+
+          // Set the neighbors of the upper/lower level:
+          float u = dog_up(mln_psite(S)(row, col));
+          float l = dog_down(mln_psite(S)(row, col));
+
+          Matrix firstOrder(3, 1);
+          firstOrder.initialize();
+
+          /************ WARNING ************/
+          /*       Maybe missing /255      */
+          /*********************************/
+
+          firstOrder.set(0, 0, n3 - n2);
+          firstOrder.set(1, 0, n4 - n1);
+          firstOrder.set(2, 0, u - l);
+
+          float product = firstOrder.dotProduct(offset);
+          float contrast = p + product / 2.0;
+
+          if (contrast < 0.03)
+            k = keypoints.erase(k);
+          else
+            k++;
         }
 
-        void findMin(value::int_s16& min, S& lower, S& upper,
-                typename S::piter& p, typename neighb2d::fwd_niter& n)
+        enough = false;
+        count = 0;
+      }
+    }
+
+    void eliminateEdgeResponses(std::list<Keypoint>& keypoints)
+    {
+      const static float bound_ratio = 12.1;
+      std::list<Keypoint>::iterator k = keypoints.begin();
+      std::list<Keypoint>::iterator end = keypoints.end();
+
+      while (k != end)
+      {
+        unsigned octave = k->getOctave();
+        unsigned gradient = k->getGradient();
+        S dog = ScaleSpace<S>::pyramid[octave][gradient];
+        int col = k->getX();
+        int row = k->getY();
+
+        if (row < 0 || col < 0
+            || static_cast<unsigned>(row) >= dog.nrows()
+            || static_cast<unsigned>(col) >= dog.ncols())
         {
-            min = (lower(p) < min) ? lower(p) : min;
-            min = (upper(p) < min) ? upper(p) : min;
-
-            for_all(n)
-            {
-                min = (lower(n) < min) ? lower(n) : min;
-                min = (upper(n) < min) ? upper(n) : min;
-            }
+          k = keypoints.erase(k);
         }
-
-        void findMax(value::int_s16& max, S& lower, S& upper,
-                typename S::piter& p, typename neighb2d::fwd_niter& n)
+        else
         {
-            max = (lower(p) > max) ? lower(p) : max;
-            max = (upper(p) > max) ? upper(p) : max;
-
-            for_all(n)
-            {
-                max = (lower(n) > max) ? lower(n) : max;
-                max = (upper(n) > max) ? upper(n) : max;
-            }
+          /* Set the neighbors:
+           *  n5  n1  n6
+           *  n2  p   n3
+           *  n7  n4  n8
+           */
+          float p = dog(mln_psite(S)(row, col));
+
+          float n1 = dog(mln_psite(S)(row - 1, col));
+          float n2 = dog(mln_psite(S)(row, col - 1));
+          float n3 = dog(mln_psite(S)(row, col + 1));
+          float n4 = dog(mln_psite(S)(row + 1, col));
+
+          float n5 = dog(mln_psite(S)(row - 1, col - 1));
+          float n6 = dog(mln_psite(S)(row - 1, col + 1));
+          float n7 = dog(mln_psite(S)(row + 1, col - 1));
+          float n8 = dog(mln_psite(S)(row + 1, col + 1));
+
+          // Set Hessian matrix and find the ratio
+
+          float dxx = n3 - 2.0 * p + n2;
+          float dyy = n4 - 2.0 * p + n1;
+          float dxy = (n8 - n6 - n7 + n5) / 4.0;
+
+          float trace = dxx + dyy;
+          float determinant = dxx * dyy - dxy * dxy;
+          float ratio = (trace * trace) / determinant;
+
+          if (determinant <= 0 || ratio >= bound_ratio)
+            k = keypoints.erase(k);
+          else
+            ++k;
         }
+      }
+    }
+
+    virtual void save()
+    {
+      ScaleSpace<S>::save("dogs-o");
+    }
+
+  private:
+    ScaleSpace<I>* ss_;
+
+    int isExtrema(S& current, value::int_s16& center,
+        typename neighb2d::fwd_niter n)
+    {
+      bool min = true;
+      bool max = true;
+
+      for_all(n)
+      {
+        min = (min && center < current(n));
+        max = (max && center > current(n));
+      }
+
+      if (min)
+        return -1;
+      else if (max)
+        return 1;
+      else
+        return 0;
+    }
+
+    void findMin(value::int_s16& min, S& lower, S& upper,
+        typename S::piter& p, typename neighb2d::fwd_niter& n)
+    {
+      min = (lower(p) < min) ? lower(p) : min;
+      min = (upper(p) < min) ? upper(p) : min;
+
+      for_all(n)
+      {
+        min = (lower(n) < min) ? lower(n) : min;
+        min = (upper(n) < min) ? upper(n) : min;
+      }
+    }
+
+    void findMax(value::int_s16& max, S& lower, S& upper,
+        typename S::piter& p, typename neighb2d::fwd_niter& n)
+    {
+      max = (lower(p) > max) ? lower(p) : max;
+      max = (upper(p) > max) ? upper(p) : max;
+
+      for_all(n)
+      {
+        max = (lower(n) > max) ? lower(n) : max;
+        max = (upper(n) > max) ? upper(n) : max;
+      }
+    }
 };
 
 #endif /* ! DOG_SPACE_HH */
diff --git a/milena/sandbox/anthony/src/main.cc b/milena/sandbox/anthony/src/main.cc
index 5cf4860..a9dd1df 100644
--- a/milena/sandbox/anthony/src/main.cc
+++ b/milena/sandbox/anthony/src/main.cc
@@ -22,58 +22,52 @@ int main(void)
   typedef image2d<value::int_s16> S;
   typedef image2d<value::rgb8> C;
 
-  // General parameters
-  std::string source("images/keith.pbm");
-  const unsigned blur_level = 5;
-  const unsigned octave_level = 4;
+  std::string source("images/tshirt.pgm");
+  const unsigned blur_level = 3;
+  const unsigned octave_level = 6;
 
   ScaleSpace<I> *ss = new ScaleSpace<I>(octave_level, blur_level);
   DoGSpace<I, S>* dogs = new DoGSpace<I, S>(ss);
   std::list<Keypoint> keypoints;
 
   I original;
-  C extrema, extrema_b,
-    extrema2, extrema2_b;
-    //improved, improved_b;
+  C extrema1, extrema1_b, extrema2, extrema2_b, extrema3, extrema3_b;
 
   io::pgm::load(original, source.c_str());
 
-  initialize(extrema_b, original);
+  initialize(extrema1_b, original);
   initialize(extrema2_b, original);
-  //initialize(improved_b, original);
+  initialize(extrema3_b, original);
 
-  extrema = data::convert(value::rgb8(), original);
+  extrema1 = data::convert(value::rgb8(), original);
   extrema2 = data::convert(value::rgb8(), original);
-  //improved = data::convert(value::rgb8(), original);
+  extrema3 = data::convert(value::rgb8(), original);
 
   // Localization
   ss->build(original);
-  //ss->save();
+  ss->save();
   dogs->build();
-  //dogs->save();
-  dogs->findKeypoints(keypoints);
+  dogs->save();
 
-  writeKeypoints(keypoints, extrema, extrema_b);
+  dogs->findKeypoints(keypoints);
+  writeKeypoints(keypoints, extrema1, extrema1_b);
+  std::cout << "Keypoints.size " << keypoints.size() << std::endl;
 
-  std::cout << "BEFORE: Low contrast discarding: " << keypoints.size() << std::endl;
   dogs->discardLowContrastKeypoints(keypoints);
-  std::cout << "AFTER: Low contrast discarding: " << keypoints.size() << std::endl;
-
-  std::cout << "BEFORE: Elimination of edge responses: " << keypoints.size() << std::endl;
-  //dogs->eliminateEdgeResponses(keypoints);
-  std::cout << "AFTER: Elimination of edge responses: " << keypoints.size() << std::endl;
-
   writeKeypoints(keypoints, extrema2, extrema2_b);
+  std::cout << "Keypoints.size " << keypoints.size() << std::endl;
 
-  //writeKeypoints(keypoints, extrema2, extrema2_b);
+  dogs->eliminateEdgeResponses(keypoints);
+  writeKeypoints(keypoints, extrema3, extrema3_b);
+  std::cout << "Keypoints.size " << keypoints.size() << std::endl;
 
   // Save
-  io::ppm::save(extrema, "output/extrema.ppm");
-  io::ppm::save(extrema_b, "output/extrema_b.ppm");
+  io::ppm::save(extrema1, "output/extrema1.ppm");
+  io::ppm::save(extrema1_b, "output/extrema1_b.ppm");
   io::ppm::save(extrema2, "output/extrema2.ppm");
   io::ppm::save(extrema2_b, "output/extrema2_b.ppm");
-  //io::ppm::save(improved, "output/extrema_improved.ppm");
-  //io::ppm::save(improved_b, "output/extrema_b_improved.ppm");
+  io::ppm::save(extrema3, "output/extrema3.ppm");
+  io::ppm::save(extrema3_b, "output/extrema3_b.ppm");
 
   return 0;
 }
diff --git a/milena/sandbox/anthony/src/scale-space.hh b/milena/sandbox/anthony/src/scale-space.hh
index e2262b6..d50c07e 100644
--- a/milena/sandbox/anthony/src/scale-space.hh
+++ b/milena/sandbox/anthony/src/scale-space.hh
@@ -10,6 +10,7 @@
 #include <mln/io/ppm/save.hh>
 #include <mln/core/alias/neighb2d.hh>
 #include <mln/literal/all.hh>
+#include <mln/linear/gaussian.hh>
 #include <mln/value/int_u8.hh>
 #include <mln/value/int_s16.hh>
 
@@ -62,7 +63,7 @@ class ScaleSpace
       }
     }
 
-    void save()
+    void save(std::string prefix = "ss-o")
     {
       std::stringstream name;
 
@@ -70,7 +71,7 @@ class ScaleSpace
       {
         for (unsigned j = 0; j < pyramid[i].size(); ++j)
         {
-          name << "output/ss-o" << i << "-" << j << ".pgm";
+          name << "output/" << prefix << i << "-" << j << ".pgm";
           io::pgm::save(pyramid[i][j], name.str());
           name.str("");
         }
@@ -92,15 +93,19 @@ class ScaleSpace
 
     void addOctave(const I& original)
     {
-      I blured;
       std::vector<I> octave;
-      float variance = sqrt(2);
+      float sigma = 1.6;
+      float k = pow(2., 1. / g);
 
-      for (unsigned i = 0; i < g; ++i)
+      octave.push_back(linear::gaussian(original, sigma));
+
+      for (unsigned i = 1; i < g + 3; ++i)
       {
-        blured = blur(original, variance);
-        variance *= sqrt(2);
-        octave.push_back(blured);
+        float sig_prev = pow(k, static_cast<float>(i-1)) * sigma;
+        float sig_total = sig_prev * k;
+        float variance = sqrt(sig_total * sig_total - sig_prev * sig_prev);
+
+        octave.push_back(linear::gaussian(original, variance));
       }
 
       pyramid.push_back(octave);
-- 
1.7.10.4