Code

add document to action events
[inkscape.git] / src / trace / siox.cpp
index d460d15579b9c8db4a65a76534b4b77f91f4001a..c69af04a165c85266a3897e98cdd8576018dac8e 100644 (file)
@@ -20,6 +20,7 @@
 #include <math.h>
 #include <stdarg.h>
 #include <map>
+#include <algorithm>
 
 
 namespace org
@@ -34,8 +35,6 @@ namespace siox
 //#  C L A B
 //########################################################################
 
-static std::map<unsigned long, CLAB> clabLookupTable;
-
 /**
  * Convert integer A, R, G, B values into an pixel value.
  */
@@ -71,24 +70,65 @@ static unsigned long getRGB(float a, float r, float g, float b)
 
 
 
-/**
- * Construct this CLAB from a packed-pixel ARGB value
- */
-CLAB::CLAB(unsigned long rgb)
+//#########################################
+//# Root approximations for large speedup.
+//# By njh!
+//#########################################
+static const int ROOT_TAB_SIZE = 16;
+static float cbrt_table[ROOT_TAB_SIZE +1];
+
+double CieLab::cbrt(double x)
+{
+    double y = cbrt_table[int(x*ROOT_TAB_SIZE )]; // assuming x \in [0, 1]
+    y = (2.0 * y + x/(y*y))/3.0;
+    y = (2.0 * y + x/(y*y))/3.0; // polish twice
+    return y;
+}
+
+static float qn_table[ROOT_TAB_SIZE +1];
+
+double CieLab::qnrt(double x)
 {
-    //First try looking up in the cache
-    std::map<unsigned long, CLAB>::iterator iter;
-    iter = clabLookupTable.find(rgb);
-    if (iter != clabLookupTable.end())
+    double y = qn_table[int(x*ROOT_TAB_SIZE )]; // assuming x \in [0, 1]
+    double Y = y*y;
+    y = (4.0*y + x/(Y*Y))/5.0;
+    Y = y*y;
+    y = (4.0*y + x/(Y*Y))/5.0; // polish twice
+    return y;
+}
+
+double CieLab::pow24(double x)
+{
+    double onetwo = x*qnrt(x);
+    return onetwo*onetwo;
+}
+
+
+static bool _clab_inited_ = false;
+void CieLab::init()
+{
+    if (!_clab_inited_)
         {
-        CLAB res = iter->second;
-        C = res.C;
-        L = res.L;
-        A = res.A;
-        B = res.B;
+        cbrt_table[0] = pow(float(1)/float(ROOT_TAB_SIZE*2), 0.3333);
+        qn_table[0]   = pow(float(1)/float(ROOT_TAB_SIZE*2), 0.2);
+        for(int i = 1; i < ROOT_TAB_SIZE +1; i++)
+            {
+            cbrt_table[i] = pow(float(i)/float(ROOT_TAB_SIZE), 0.3333);
+            qn_table[i] = pow(float(i)/float(ROOT_TAB_SIZE), 0.2);
+            }
+        _clab_inited_ = true;
         }
+}
+       
 
 
+/**
+ * Construct this CieLab from a packed-pixel ARGB value
+ */
+CieLab::CieLab(unsigned long rgb)
+{
+    init();
+
     int ir  = (rgb>>16) & 0xff;
     int ig  = (rgb>> 8) & 0xff;
     int ib  = (rgb    ) & 0xff;
@@ -97,46 +137,50 @@ CLAB::CLAB(unsigned long rgb)
     float fg = ((float)ig) / 255.0;
     float fb = ((float)ib) / 255.0;
 
+    //printf("fr:%f fg:%f fb:%f\n", fr, fg, fb);
     if (fr > 0.04045)
-        fr = (float) pow((fr + 0.055) / 1.055, 2.4);
+        //fr = (float) pow((fr + 0.055) / 1.055, 2.4);
+        fr = (float) pow24((fr + 0.055) / 1.055);
     else
         fr = fr / 12.92;
 
     if (fg > 0.04045)
-        fg = (float) pow((fg + 0.055) / 1.055, 2.4);
+        //fg = (float) pow((fg + 0.055) / 1.055, 2.4);
+        fg = (float) pow24((fg + 0.055) / 1.055);
     else
         fg = fg / 12.92;
 
     if (fb > 0.04045)
-        fb = (float) pow((fb + 0.055) / 1.055, 2.4);
+        //fb = (float) pow((fb + 0.055) / 1.055, 2.4);
+        fb = (float) pow24((fb + 0.055) / 1.055);
     else
         fb = fb / 12.92;
 
-    fr = fr * 100.0;
-    fg = fg * 100.0;
-    fb = fb * 100.0;
-
     // Use white = D65
-    float x = fr * 0.4124 + fg * 0.3576 + fb * 0.1805;
-    float y = fr * 0.2126 + fg * 0.7152 + fb * 0.0722;
-    float z = fr * 0.0193 + fg * 0.1192 + fb * 0.9505;
+    const float x = fr * 0.4124 + fg * 0.3576 + fb * 0.1805;
+    const float y = fr * 0.2126 + fg * 0.7152 + fb * 0.0722;
+    const float z = fr * 0.0193 + fg * 0.1192 + fb * 0.9505;
 
-    float vx = x /  95.047;
-    float vy = y / 100.000;
-    float vz = z / 108.883;
+    float vx = x / 0.95047;
+    float vy = y;
+    float vz = z / 1.08883;
 
+    //printf("vx:%f vy:%f vz:%f\n", vx, vy, vz);
     if (vx > 0.008856)
-        vx = (float) pow(vx, 0.3333);
+        //vx = (float) pow(vx, 0.3333);
+        vx = (float) cbrt(vx);
     else
         vx = (7.787 * vx) + (16.0 / 116.0);
 
     if (vy > 0.008856)
-        vy = (float) pow(vy, 0.3333);
+        //vy = (float) pow(vy, 0.3333);
+        vy = (float) cbrt(vy);
     else
         vy = (7.787 * vy) + (16.0 / 116.0);
 
     if (vz > 0.008856)
-        vz = (float) pow(vz, 0.3333);
+        //vz = (float) pow(vz, 0.3333);
+        vz = (float) cbrt(vz);
     else
         vz = (7.787 * vz) + (16.0 / 116.0);
 
@@ -144,18 +188,14 @@ CLAB::CLAB(unsigned long rgb)
     L = 116.0 * vy - 16.0;
     A = 500.0 * (vx - vy);
     B = 200.0 * (vy - vz);
-
-    // Cache for next time
-    clabLookupTable[rgb] = *this;
-
 }
 
 
 
 /**
- * Return this CLAB's value a a packed-pixel ARGB value
+ * Return this CieLab's value converted to a packed-pixel ARGB value
  */
-unsigned long CLAB::toRGB()
+unsigned long CieLab::toRGB()
 {
     float vy = (L + 16.0) / 116.0;
     float vx = A / 500.0 + vy;
@@ -180,13 +220,8 @@ unsigned long CLAB::toRGB()
     else
         vz = (vz - 16.0 / 116.0) / 7.787;
 
-    float x =  95.047 * vx; //use white = D65
-    float y = 100.000 * vy;
-    float z = 108.883 * vz;
-
-    vx = x / 100.0;
-    vy = y / 100.0;
-    vz = z / 100.0;
+    vx *= 0.95047; //use white = D65
+    vz *= 1.08883;
 
     float vr =(float)(vx *  3.2406 + vy * -1.5372 + vz * -0.4986);
     float vg =(float)(vx * -0.9689 + vy *  1.8758 + vz *  0.0415);
@@ -212,31 +247,41 @@ unsigned long CLAB::toRGB()
 
 
 /**
- * Computes squared euclidian distance in CLAB space for two colors
+ * Squared Euclidian distance between this and another color
+ */
+float CieLab::diffSq(const CieLab &other)
+{
+    float sum=0.0;
+    sum += (L - other.L) * (L - other.L);
+    sum += (A - other.A) * (A - other.A);
+    sum += (B - other.B) * (B - other.B);
+    return sum;
+}
+
+/**
+ * Computes squared euclidian distance in CieLab space for two colors
  * given as RGB values.
  */
-float CLAB::diffSq(unsigned int rgb1, unsigned int rgb2)
+float CieLab::diffSq(unsigned int rgb1, unsigned int rgb2)
 {
-    CLAB c1(rgb1);
-    CLAB c2(rgb2);
-    float euclid=0.0f;
-    euclid += (c1.L - c2.L) * (c1.L - c2.L);
-    euclid += (c1.A - c2.A) * (c1.A - c2.A);
-    euclid += (c1.B - c2.B) * (c1.B - c2.B);
+    CieLab c1(rgb1);
+    CieLab c2(rgb2);
+    float euclid = c1.diffSq(c2);
     return euclid;
 }
 
 
 /**
- * Computes squared euclidian distance in CLAB space for two colors
+ * Computes squared euclidian distance in CieLab space for two colors
  * given as RGB values.
  */
-float CLAB::diff(unsigned int rgb0, unsigned int rgb1)
+float CieLab::diff(unsigned int rgb0, unsigned int rgb1)
 {
     return (float) sqrt(diffSq(rgb0, rgb1));
 }
 
 
+
 //########################################################################
 //#  T U P E L
 //########################################################################
@@ -259,25 +304,25 @@ public:
     Tupel(float minBgDistArg, long indexMinBgArg,
           float minFgDistArg, long indexMinFgArg)
         {
-       minBgDist  = minBgDistArg;
-       indexMinBg = indexMinBgArg;
-       minFgDist  = minFgDistArg;
-       indexMinFg = indexMinFgArg;
+        minBgDist  = minBgDistArg;
+        indexMinBg = indexMinBgArg;
+        minFgDist  = minFgDistArg;
+        indexMinFg = indexMinFgArg;
         }
     Tupel(const Tupel &other)
         {
-       minBgDist  = other.minBgDist;
-       indexMinBg = other.indexMinBg;
-       minFgDist  = other.minFgDist;
-       indexMinFg = other.indexMinFg;
+        minBgDist  = other.minBgDist;
+        indexMinBg = other.indexMinBg;
+        minFgDist  = other.minFgDist;
+        indexMinFg = other.indexMinFg;
         }
     Tupel &operator=(const Tupel &other)
         {
-       minBgDist  = other.minBgDist;
-       indexMinBg = other.indexMinBg;
-       minFgDist  = other.minFgDist;
-       indexMinFg = other.indexMinFg;
-       return *this;
+        minBgDist  = other.minBgDist;
+        indexMinBg = other.indexMinBg;
+        minFgDist  = other.minFgDist;
+        indexMinFg = other.indexMinFg;
+        return *this;
         }
     virtual ~Tupel()
         {}
@@ -332,6 +377,24 @@ SioxImage::~SioxImage()
     if (cmdata)  delete[] cmdata;
 }
 
+/**
+ * Error logging
+ */
+void SioxImage::error(char *fmt, ...)
+{
+    char msgbuf[256];
+    va_list args;
+    va_start(args, fmt);
+    vsnprintf(msgbuf, 255, fmt, args);
+    va_end(args) ;
+#ifdef HAVE_GLIB
+    g_warning("SioxImage error: %s\n", msgbuf);
+#else
+    fprintf(stderr, "SioxImage error: %s\n", msgbuf);
+#endif
+}
+
+
 /**
  * Returns true if the previous operation on this image
  * was successful, else false.
@@ -360,8 +423,12 @@ void SioxImage::setPixel(unsigned int x,
                          unsigned int y,
                          unsigned int pixval)
 {
-    if (x > width || y > height)
+    if (x >= width || y >= height)
+        {
+        error("setPixel: out of bounds (%d,%d)/(%d,%d)",
+                   x, y, width, height);
         return;
+        }
     unsigned long offset = width * y + x;
     pixdata[offset] = pixval; 
 }
@@ -376,8 +443,12 @@ void SioxImage::setPixel(unsigned int x, unsigned int y,
                          unsigned int g,
                          unsigned int b)
 {
-    if (x > width || y > height)
+    if (x >= width || y >= height)
+        {
+        error("setPixel: out of bounds (%d,%d)/(%d,%d)",
+                   x, y, width, height);
         return;
+        }
     unsigned long offset = width * y + x;
     unsigned int pixval = ((a << 24) & 0xff000000) |
                           ((r << 16) & 0x00ff0000) |
@@ -394,8 +465,12 @@ void SioxImage::setPixel(unsigned int x, unsigned int y,
  */
 unsigned int SioxImage::getPixel(unsigned int x, unsigned int y)
 {
-    if (x > width || y > height)
+    if (x >= width || y >= height)
+        {
+        error("getPixel: out of bounds (%d,%d)/(%d,%d)",
+                   x, y, width, height);
         return 0L;
+        }
     unsigned long offset = width * y + x;
     return pixdata[offset]; 
 }
@@ -416,8 +491,12 @@ void SioxImage::setConfidence(unsigned int x,
                               unsigned int y,
                               float confval)
 {
-    if (x > width || y > height)
+    if (x >= width || y >= height)
+        {
+        error("setConfidence: out of bounds (%d,%d)/(%d,%d)",
+                   x, y, width, height);
         return;
+        }
     unsigned long offset = width * y + x;
     cmdata[offset] = confval; 
 }
@@ -428,8 +507,12 @@ void SioxImage::setConfidence(unsigned int x,
  */
 float SioxImage::getConfidence(unsigned int x, unsigned int y)
 {
-    if (x > width || y > height)
+    if (x >= width || y >= height)
+        {
+        g_warning("getConfidence: out of bounds (%d,%d)/(%d,%d)",
+                   x, y, width, height);
         return 0.0;
+        }
     unsigned long offset = width * y + x;
     return cmdata[offset]; 
 }
@@ -574,16 +657,19 @@ SioxImage::SioxImage(GdkPixbuf *buf)
  */
 GdkPixbuf *SioxImage::getGdkPixbuf()
 {
+    bool has_alpha = true;
+    int n_channels = has_alpha ? 4 : 3;
+
     guchar *pixdata = (guchar *)
-          malloc(sizeof(guchar) * width * height * 3);
+          malloc(sizeof(guchar) * width * height * n_channels);
     if (!pixdata)
         return NULL;
 
-    int n_channels = 3;
-    int rowstride  = width * 3;
+    int rowstride  = width * n_channels;
 
-    GdkPixbuf *buf = gdk_pixbuf_new_from_data(pixdata, GDK_COLORSPACE_RGB,
-                        0, 8, width, height,
+    GdkPixbuf *buf = gdk_pixbuf_new_from_data(pixdata,
+                        GDK_COLORSPACE_RGB,
+                        has_alpha, 8, width, height,
                         rowstride, NULL, NULL);
 
     //### Fill in the cells with RGB values
@@ -594,9 +680,13 @@ GdkPixbuf *SioxImage::getGdkPixbuf()
         for (unsigned x=0 ; x < width ; x++)
             {
             unsigned int rgb = getPixel(x, y);
-            p[0] = (rgb >> 16) & 0xff;
-            p[1] = (rgb >>  8) & 0xff;
-            p[2] = (rgb      ) & 0xff;
+            p[0] = (rgb >> 16) & 0xff;//r
+            p[1] = (rgb >>  8) & 0xff;//g
+            p[2] = (rgb      ) & 0xff;//b
+            if ( n_channels > 3 )
+                {
+                p[3] = (rgb >> 24) & 0xff;//a
+                }
             p += n_channels;
             }
         row += rowstride;
@@ -647,8 +737,18 @@ const float Siox::CERTAIN_BACKGROUND_CONFIDENCE=0.0f;
  *  Construct a Siox engine
  */
 Siox::Siox()
+{
+    sioxObserver = NULL;
+    init();
+}
+
+/**
+ *  Construct a Siox engine
+ */
+Siox::Siox(SioxObserver *observer)
 {
     init();
+    sioxObserver = observer;
 }
 
 
@@ -697,6 +797,27 @@ void Siox::trace(char *fmt, ...)
 
 
 
+/**
+ * Progress reporting
+ */
+bool Siox::progressReport(float percentCompleted)
+{
+    if (!sioxObserver)
+        return true;
+
+    bool ret = sioxObserver->progress(percentCompleted);
+
+    if (!ret)
+      {
+      trace("User selected abort");
+      keepGoing = false;
+      }
+
+    return ret;
+}
+
+
+
 
 /**
  *  Extract the foreground of the original image, according
@@ -705,7 +826,10 @@ void Siox::trace(char *fmt, ...)
 SioxImage Siox::extractForeground(const SioxImage &originalImage,
                                   unsigned int backgroundFillColor)
 {
+    trace("### Start");
+
     init();
+    keepGoing = true;
 
     SioxImage workImage = originalImage;
 
@@ -720,35 +844,76 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
     trace("### Creating signatures");
 
     //#### create color signatures
-    std::vector<CLAB> knownBg;
-    std::vector<CLAB> knownFg;
-    for (int x = 0 ; x < workImage.getWidth() ; x++)
-        for (int y = 0 ; y < workImage.getHeight() ; y++)
+    std::vector<CieLab> knownBg;
+    std::vector<CieLab> knownFg;
+    CieLab *imageClab = new CieLab[pixelCount];
+    for (unsigned long i=0 ; i<pixelCount ; i++)
+        {
+        float conf = cm[i];
+        unsigned int pix = image[i];
+        CieLab lab(pix);
+        imageClab[i] = lab;
+        if (conf <= BACKGROUND_CONFIDENCE)
+            knownBg.push_back(lab);
+        else if (conf >= FOREGROUND_CONFIDENCE)
+            knownFg.push_back(lab);
+        }
+
+    /*
+    std::vector<CieLab> imageClab;
+    for (int y = 0 ; y < workImage.getHeight() ; y++)
+        for (int x = 0 ; x < workImage.getWidth() ; x++)
             {
             float cm = workImage.getConfidence(x, y);
             unsigned int pix = workImage.getPixel(x, y);
+            CieLab lab(pix);
+            imageClab.push_back(lab);
             if (cm <= BACKGROUND_CONFIDENCE)
-                knownBg.push_back(pix); //note: uses CLAB(rgb)
+                knownBg.push_back(lab); //note: uses CieLab(rgb)
             else if (cm >= FOREGROUND_CONFIDENCE)
-                knownFg.push_back(pix);
+                knownFg.push_back(lab);
             }
+    */
+
+    if (!progressReport(10.0))
+        {
+        error("User aborted");
+        workImage.setValid(false);
+        delete[] imageClab;
+        delete[] labelField;
+        return workImage;
+        }
 
-    trace("knownBg:%d knownFg:%d", knownBg.size(), knownFg.size());
+    trace("knownBg:%zu knownFg:%zu", knownBg.size(), knownFg.size());
 
 
-    std::vector<CLAB> bgSignature ;
+    std::vector<CieLab> bgSignature ;
     if (!colorSignature(knownBg, bgSignature, 3))
         {
         error("Could not create background signature");
         workImage.setValid(false);
+        delete[] imageClab;
+        delete[] labelField;
+        return workImage;
+        }
+
+    if (!progressReport(30.0))
+        {
+        error("User aborted");
+        workImage.setValid(false);
+        delete[] imageClab;
+        delete[] labelField;
         return workImage;
         }
-    std::vector<CLAB> fgSignature ;
+
+
+    std::vector<CieLab> fgSignature ;
     if (!colorSignature(knownFg, fgSignature, 3))
         {
         error("Could not create foreground signature");
-        delete[] labelField;
         workImage.setValid(false);
+        delete[] imageClab;
+        delete[] labelField;
         return workImage;
         }
 
@@ -758,17 +923,47 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
         {
         // segmentation impossible
         error("Signature size is < 1.  Segmentation is impossible");
+        workImage.setValid(false);
+        delete[] imageClab;
         delete[] labelField;
+        return workImage;
+        }
+
+    if (!progressReport(30.0))
+        {
+        error("User aborted");
         workImage.setValid(false);
+        delete[] imageClab;
+        delete[] labelField;
         return workImage;
         }
 
+
     // classify using color signatures,
     // classification cached in hashmap for drb and speedup purposes
+    trace("### Analyzing image");
+
     std::map<unsigned int, Tupel> hs;
+    
+    unsigned int progressResolution = pixelCount / 10;
 
     for (unsigned int i=0; i<pixelCount; i++)
         {
+        if (i % progressResolution == 0)
+            {
+            float progress = 
+                30.0 + 60.0 * (float)i / (float)pixelCount;
+            //trace("### progress:%f", progress);
+            if (!progressReport(progress))
+                {
+                error("User aborted");
+                delete[] imageClab;
+                delete[] labelField;
+                workImage.setValid(false);
+                return workImage;
+                }
+            }
+
         if (cm[i] >= FOREGROUND_CONFIDENCE)
             {
             cm[i] = CERTAIN_FOREGROUND_CONFIDENCE;
@@ -783,17 +978,17 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
             std::map<unsigned int, Tupel>::iterator iter = hs.find(i);
             if (iter != hs.end()) //found
                 {
-                Tupel tupel = iter->second;
+                Tupel tupel  = iter->second;
                 isBackground = tupel.minBgDist <= tupel.minFgDist;
                 }
             else
                 {
-                CLAB lab(image[i]);
-                float minBg = sqrEuclidianDist(lab, bgSignature[0]);
-                int minIndex=0;
+                CieLab lab   = imageClab[i];
+                float minBg  = lab.diffSq(bgSignature[0]);
+                int minIndex = 0;
                 for (unsigned int j=1; j<bgSignature.size() ; j++)
                     {
-                    float d = sqrEuclidianDist(lab, bgSignature[j]);
+                    float d = lab.diffSq(bgSignature[j]);
                     if (d<minBg)
                         {
                         minBg    = d;
@@ -803,11 +998,11 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
                 Tupel tupel(0.0f, 0,  0.0f, 0);
                 tupel.minBgDist  = minBg;
                 tupel.indexMinBg = minIndex;
-                float minFg = 1.0e6f;
-                minIndex = -1;
+                float minFg      = 1.0e6f;
+                minIndex         = -1;
                 for (unsigned int j = 0 ; j < fgSignature.size() ; j++)
                     {
-                    float d = sqrEuclidianDist(lab, fgSignature[j]);
+                    float d = lab.diffSq(fgSignature[j]);
                     if (d < minFg)
                         {
                         minFg    = d;
@@ -818,7 +1013,7 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
                 tupel.indexMinFg = minIndex;
                 if (fgSignature.size() == 0)
                     {
-                    isBackground=(minBg <= clusterSize);
+                    isBackground = (minBg <= clusterSize);
                     // remove next line to force behaviour of old algorithm
                     //error("foreground signature does not exist");
                     //delete[] labelField;
@@ -839,16 +1034,20 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
             }
         }
 
+
+    delete[] imageClab;
+
     trace("### postProcessing");
 
-    //## postprocessing
-    smooth(cm, width, height, 0.33f, 0.33f, 0.33f); // average
+
+    //#### postprocessing
+    smooth(cm, width, height, 0.333f, 0.333f, 0.333f); // average
     normalizeMatrix(cm, pixelCount);
     erode(cm, width, height);
     keepOnlyLargeComponents(UNKNOWN_REGION_CONFIDENCE, 1.0/*sizeFactorToKeep*/);
 
-    for (int i=0; i < 2/*smoothness*/; i++)
-        smooth(cm, width, height, 0.33f, 0.33f, 0.33f); // average
+    //for (int i=0; i < 2/*smoothness*/; i++)
+    //    smooth(cm, width, height, 0.333f, 0.333f, 0.333f); // average
 
     normalizeMatrix(cm, pixelCount);
 
@@ -864,20 +1063,27 @@ SioxImage Siox::extractForeground(const SioxImage &originalImage,
     fillColorRegions();
     dilate(cm, width, height);
 
-    delete[] labelField;
+    if (!progressReport(100.0))
+        {
+        error("User aborted");
+        delete[] labelField;
+        workImage.setValid(false);
+        return workImage;
+        }
 
-    //#### Yaay.  We are done.  Now clear everything but the background
-    for (unsigned int y = 0 ; y < height ; y++)
-        for (unsigned int x = 0 ; x < width ; x++)
-            {
-            float conf = workImage.getConfidence(x, y);
-            if (conf < FOREGROUND_CONFIDENCE)
-                {
-                workImage.setPixel(x, y, backgroundFillColor);
-                }
-            }
+
+    //#### We are done.  Now clear everything but the background
+    for (unsigned long i = 0; i<pixelCount ; i++)
+        {
+        float conf = cm[i];
+        if (conf < FOREGROUND_CONFIDENCE)
+            image[i] = backgroundFillColor;
+        }
+
+    delete[] labelField;
 
     trace("### Done");
+    keepGoing = false;
     return workImage;
 }
 
@@ -920,7 +1126,7 @@ void Siox::cleanup()
  *  Stage 1 of the color signature work.  'dims' will be either
  *  2 for grays, or 3 for colors
  */
-void Siox::colorSignatureStage1(CLAB *points,
+void Siox::colorSignatureStage1(CieLab *points,
                                 unsigned int leftBase,
                                 unsigned int rightBase,
                                 unsigned int recursionDepth,
@@ -929,7 +1135,7 @@ void Siox::colorSignatureStage1(CLAB *points,
 {
 
     unsigned int currentDim = recursionDepth % dims;
-    CLAB point = points[leftBase];
+    CieLab point = points[leftBase];
     float min = point(currentDim);
     float max = min;
 
@@ -986,7 +1192,7 @@ void Siox::colorSignatureStage1(CLAB *points,
     else
         {
         //create a leaf
-        CLAB newpoint;
+        CieLab newpoint;
 
         newpoint.C = rightBase - leftBase;
 
@@ -1009,7 +1215,7 @@ void Siox::colorSignatureStage1(CLAB *points,
 /**
  *  Stage 2 of the color signature work
  */
-void Siox::colorSignatureStage2(CLAB         *points,
+void Siox::colorSignatureStage2(CieLab         *points,
                                 unsigned int leftBase,
                                 unsigned int rightBase,
                                 unsigned int recursionDepth,
@@ -1020,7 +1226,7 @@ void Siox::colorSignatureStage2(CLAB         *points,
 
   
     unsigned int currentDim = recursionDepth % dims;
-    CLAB point = points[leftBase];
+    CieLab point = points[leftBase];
     float min = point(currentDim);
     float max = min;
 
@@ -1084,7 +1290,7 @@ void Siox::colorSignatureStage2(CLAB         *points,
         if ((float)sum >= threshold)
             {
             float scale = (float)(rightBase - leftBase);
-            CLAB newpoint;
+            CieLab newpoint;
 
             for (; leftBase < rightBase; leftBase++)
                 newpoint.add(points[leftBase]);
@@ -1102,8 +1308,8 @@ void Siox::colorSignatureStage2(CLAB         *points,
 /**
  *  Main color signature method
  */
-bool Siox::colorSignature(const std::vector<CLAB> &inputVec,
-                          std::vector<CLAB> &result,
+bool Siox::colorSignature(const std::vector<CieLab> &inputVec,
+                          std::vector<CieLab> &result,
                           const unsigned int dims)
 {
 
@@ -1112,7 +1318,7 @@ bool Siox::colorSignature(const std::vector<CLAB> &inputVec,
     if (length < 1) // no error. just don't do anything
         return true;
 
-    CLAB *input = (CLAB *) malloc(length * sizeof(CLAB));
+    CieLab *input = (CieLab *) malloc(length * sizeof(CieLab));
 
     if (!input)
         {
@@ -1219,7 +1425,7 @@ int Siox::depthFirstSearch(int startPos,
 
         // check all four neighbours
         int left = pos - 1;
-        if (x-1>=0 && labelField[left]==-1 && cm[left]>=threshold)
+        if (((int)x)-1>=0 && labelField[left]==-1 && cm[left]>=threshold)
             {
             labelField[left]=curLabel;
             componentSize++;
@@ -1235,7 +1441,7 @@ int Siox::depthFirstSearch(int startPos,
             }
 
         int top = pos - width;
-        if (y-1>=0 && labelField[top]==-1 && cm[top]>=threshold)
+        if (((int)y)-1>=0 && labelField[top]==-1 && cm[top]>=threshold)
             {
             labelField[top]=curLabel;
             componentSize++;
@@ -1290,8 +1496,8 @@ void Siox::fillColorRegions()
             unsigned int y=pos / width;
             // check all four neighbours
             int left = pos-1;
-            if (x-1 >= 0 && labelField[left] == -1
-                        && CLAB::diff(image[left], origColor)<1.0)
+            if (((int)x)-1 >= 0 && labelField[left] == -1
+                        && CieLab::diff(image[left], origColor)<1.0)
                 {
                 labelField[left]=curLabel;
                 cm[left]=CERTAIN_FOREGROUND_CONFIDENCE;
@@ -1300,7 +1506,7 @@ void Siox::fillColorRegions()
                 }
             int right = pos+1;
             if (x+1 < width && labelField[right]==-1
-                        && CLAB::diff(image[right], origColor)<1.0)
+                        && CieLab::diff(image[right], origColor)<1.0)
                 {
                 labelField[right]=curLabel;
                 cm[right]=CERTAIN_FOREGROUND_CONFIDENCE;
@@ -1308,8 +1514,8 @@ void Siox::fillColorRegions()
                 pixelsToVisit.push_back(right);
                 }
             int top = pos - width;
-            if (y-1>=0 && labelField[top]==-1
-                        && CLAB::diff(image[top], origColor)<1.0)
+            if (((int)y)-1>=0 && labelField[top]==-1
+                        && CieLab::diff(image[top], origColor)<1.0)
                 {
                 labelField[top]=curLabel;
                 cm[top]=CERTAIN_FOREGROUND_CONFIDENCE;
@@ -1318,7 +1524,7 @@ void Siox::fillColorRegions()
                 }
             int bottom = pos + width;
             if (y+1 < height && labelField[bottom]==-1
-                        && CLAB::diff(image[bottom], origColor)<1.0)
+                        && CieLab::diff(image[bottom], origColor)<1.0)
                 {
                 labelField[bottom]=curLabel;
                 cm[bottom]=CERTAIN_FOREGROUND_CONFIDENCE;
@@ -1429,7 +1635,6 @@ void Siox::erode(float *cm, int xres, int yres)
 
 
 
-
 /**
  * Normalizes the matrix to values to [0..1].
  */
@@ -1437,8 +1642,10 @@ void Siox::normalizeMatrix(float *cm, int cmSize)
 {
     float max= -1000000.0f;
     for (int i=0; i<cmSize; i++)
-        if (max<cm[i] > max)
-            max=cm[i];
+        if (cm[i] > max) max=cm[i];
+        
+    //good to use STL, but max() is not iterative
+    //float max = *std::max(cm, cm + cmSize);
 
     if (max<=0.0 || max==1.0)
         return;
@@ -1513,20 +1720,6 @@ float Siox::sqrEuclidianDist(float *p, int pSize, float *q)
     return sum;
 }
 
-/**
- * Squared Euclidian distance of p and q.
- */
-float Siox::sqrEuclidianDist(const CLAB &p, const CLAB &q)
-{
-    float sum=0;
-    sum += (p.L - q.L) * (p.L - q.L);
-    sum += (p.A - q.A) * (p.A - q.A);
-    sum += (p.B - q.B) * (p.B - q.B);
-    return sum;
-}
-
-
-