[Digikam-devel] extragear/graphics/digikam/libs/dimg/filters/fx

Gilles Caulier caulier.gilles at gmail.com
Fri Nov 12 16:42:01 GMT 2010


SVN commit 1196146 by cgilles:

Andy, this is not understadable.
All CImg::*blur() method crash under MacOsX. and i don't know why...
Probably, this is fixed with last CImg 1.4.x release, as digiKam still use 1.3.0...
but we cannot update because all Greystoration algorithm have been removed from CImg and migrated to GMic library 
The solution is to port greystoration code to GMic, as it have been recommended by CImg author in the past by a private mail.
But it's a long and complex task.
Note : Greystoration tools do not crash under MAC Os X !!! I'm lost...
So, I restore old gaussian blur algorithm for Mac only...
CCMAIL: digikam-devel at kde.org


 M  +266 -3    blurfilter.cpp  
 M  +35 -1     blurfilter.h  


--- trunk/extragear/graphics/digikam/libs/dimg/filters/fx/blurfilter.cpp #1196145:1196146
@@ -66,13 +66,16 @@
 
 void BlurFilter::filterImage()
 {
+#if defined(__MACOSX__) || defined(__APPLE__)
     gaussianBlurImage(m_orgImage.bits(), m_orgImage.width(), m_orgImage.height(),
+                      m_orgImage.sixteenBit(), (int)(m_radius*10.0));
+#else
+    cimgBlurImage(m_orgImage.bits(), m_orgImage.width(), m_orgImage.height(),
                       m_orgImage.sixteenBit(), m_radius);
+#endif
 }
 
-/** Function to apply the Gaussian Blur on an image. 
- */
-void BlurFilter::gaussianBlurImage(uchar* data, int width, int height, bool sixteenBit, double radius)
+void BlurFilter::cimgBlurImage(uchar* data, int width, int height, bool sixteenBit, double radius)
 {
     if (!data || !width || !height)
     {
@@ -143,4 +146,264 @@
     }
 }
 
+void BlurFilter::gaussianBlurImage(uchar* data, int width, int height, bool sixteenBit, int radius)
+{
+    if (!data || !width || !height)
+    {
+        kWarning(50003) << ("DImgGaussianBlur::gaussianBlurImage: no image data available!") << endl;
+        return;
+    }
+
+    if (radius > 100) radius = 100;
+    if (radius <= 0)
+    {
+        m_destImage = m_orgImage;
+        return;
+    }
+
+    // Gaussian kernel computation using the Radius parameter.
+
+    int          nKSize, nCenter;
+    double       x, sd, factor, lnsd, lnfactor;
+    register int i, j, n, h, w;
+
+    nKSize      = 2 * radius + 1;
+    nCenter     = nKSize / 2;
+    int *Kernel = new int[nKSize];
+
+    lnfactor = (4.2485 - 2.7081) / 10 * nKSize + 2.7081;
+    lnsd     = (0.5878 + 0.5447) / 10 * nKSize - 0.5447;
+    factor   = exp (lnfactor);
+    sd       = exp (lnsd);
+
+    for (i = 0; !runningFlag() && (i < nKSize); ++i)
+    {
+        x = sqrt ((i - nCenter) * (i - nCenter));
+        Kernel[i] = (int)(factor * exp (-0.5 * pow ((x / sd), 2)) / (sd * sqrt (2.0 * M_PI)));
+    }
+
+    // Now, we need to convolve the image descriptor.
+    // I've worked hard here, but I think this is a very smart
+    // way to convolve an array, its very hard to explain how I reach
+    // this, but the trick here its to store the sum used by the
+    // previous pixel, so we sum with the other pixels that wasn't get.
+
+    int nSumA, nSumR, nSumG, nSumB, nCount, progress;
+    int nKernelWidth = radius * 2 + 1;
+
+    // We need to alloc a 2d array to help us to store the values
+
+    int** arrMult = Alloc2DArray (nKernelWidth, sixteenBit ? 65536 : 256);
+
+    for (i = 0; !runningFlag() && (i < nKernelWidth); ++i)
+        for (j = 0; !runningFlag() && (j < (sixteenBit ? 65536 : 256)); ++j)
+            arrMult[i][j] = j * Kernel[i];
+
+        // We need to copy our bits to blur bits
+
+    uchar* pOutBits = m_destImage.bits();
+    uchar* pBlur    = new uchar[m_destImage.numBytes()];
+
+    memcpy (pBlur, data, m_destImage.numBytes());
+
+    // We need to initialize all the loop and iterator variables
+
+    nSumA = nSumR = nSumG = nSumB = nCount = i = j = 0;
+    unsigned short* data16     = (unsigned short*)data;
+    unsigned short* pBlur16    = (unsigned short*)pBlur;
+    unsigned short* pOutBits16 = (unsigned short*)pOutBits;
+
+    // Now, we enter in the main loop
+
+    for (h = 0; !runningFlag() && (h < height); ++h)
+    {
+        for (w = 0; !runningFlag() && (w < width); ++w, i+=4)
+        {
+            if (!sixteenBit)        // 8 bits image.
+            {
+                uchar *org, *dst;
+
+                // first of all, we need to blur the horizontal lines
+
+                for (n = -radius; !runningFlag() && (n <= radius); ++n)
+                {
+                    // if is inside...
+                    if (IsInside (width, height, w + n, h))
+                    {
+                        // we points to the pixel
+                        j = i + 4*n;
+
+                        // finally, we sum the pixels using a method similar to assigntables
+
+                        org = &data[j];
+                        nSumA += arrMult[n + radius][org[3]];
+                        nSumR += arrMult[n + radius][org[2]];
+                        nSumG += arrMult[n + radius][org[1]];
+                        nSumB += arrMult[n + radius][org[0]];
+
+                        // we need to add to the counter, the kernel value
+                        nCount += Kernel[n + radius];
+                    }
+                }
+
+                if (nCount == 0) nCount = 1;
+
+                // now, we return to blur bits the horizontal blur values
+                dst    = &pBlur[i];
+                dst[3] = (uchar)CLAMP (nSumA / nCount, 0, 255);
+                dst[2] = (uchar)CLAMP (nSumR / nCount, 0, 255);
+                dst[1] = (uchar)CLAMP (nSumG / nCount, 0, 255);
+                dst[0] = (uchar)CLAMP (nSumB / nCount, 0, 255);
+
+                // ok, now we reinitialize the variables
+                nSumA = nSumR = nSumG = nSumB = nCount = 0;
+            }
+            else                 // 16 bits image.
+            {
+                unsigned short *org, *dst;
+
+                // first of all, we need to blur the horizontal lines
+
+                for (n = -radius; !runningFlag() && (n <= radius); ++n)
+                {
+                    // if is inside...
+                    if (IsInside (width, height, w + n, h))
+                    {
+                        // we points to the pixel
+                        j = i + 4*n;
+
+                        // finally, we sum the pixels using a method similar to assigntables
+
+                        org = &data16[j];
+                        nSumA += arrMult[n + radius][org[3]];
+                        nSumR += arrMult[n + radius][org[2]];
+                        nSumG += arrMult[n + radius][org[1]];
+                        nSumB += arrMult[n + radius][org[0]];
+
+                        // we need to add to the counter, the kernel value
+                        nCount += Kernel[n + radius];
+                    }
+                }
+
+                if (nCount == 0) nCount = 1;
+
+                // now, we return to blur bits the horizontal blur values
+                dst    = &pBlur16[i];
+                dst[3] = (unsigned short)CLAMP (nSumA / nCount, 0, 65535);
+                dst[2] = (unsigned short)CLAMP (nSumR / nCount, 0, 65535);
+                dst[1] = (unsigned short)CLAMP (nSumG / nCount, 0, 65535);
+                dst[0] = (unsigned short)CLAMP (nSumB / nCount, 0, 65535);
+
+                // ok, now we reinitialize the variables
+                nSumA = nSumR = nSumG = nSumB = nCount = 0;
+            }
+        }
+
+        progress = (int) (((double)h * 50.0) / height);
+        if ( progress%5 == 0 )
+            postProgress( progress );
+    }
+
+    // getting the blur bits, we initialize position variables
+    i = j = 0;
+
+    // We enter in the second main loop
+    for (w = 0; !runningFlag() && (w < width); ++w, i = w*4)
+    {
+        for (h = 0; !runningFlag() && (h < height); ++h, i += width*4)
+        {
+            if (!sixteenBit)        // 8 bits image.
+            {
+                uchar *org, *dst;
+
+                // first of all, we need to blur the vertical lines
+                for (n = -radius; !runningFlag() && (n <= radius); ++n)
+                {
+                    // if is inside...
+                    if (IsInside(width, height, w, h + n))
+                    {
+                        // we points to the pixel
+                        j = i + n * 4 * width;
+
+                        // finally, we sum the pixels using a method similar to assigntables
+                        org = &pBlur[j];
+                        nSumA += arrMult[n + radius][org[3]];
+                        nSumR += arrMult[n + radius][org[2]];
+                        nSumG += arrMult[n + radius][org[1]];
+                        nSumB += arrMult[n + radius][org[0]];
+
+                        // we need to add to the counter, the kernel value
+                        nCount += Kernel[n + radius];
+                    }
+                }
+
+                if (nCount == 0) nCount = 1;
+
+                // To preserve Alpha channel.
+                memcpy (&pOutBits[i], &data[i], 4);
+
+                // now, we return to bits the vertical blur values
+                dst    = &pOutBits[i];
+                dst[3] = (uchar)CLAMP (nSumA / nCount, 0, 255);
+                dst[2] = (uchar)CLAMP (nSumR / nCount, 0, 255);
+                dst[1] = (uchar)CLAMP (nSumG / nCount, 0, 255);
+                dst[0] = (uchar)CLAMP (nSumB / nCount, 0, 255);
+
+                // ok, now we reinitialize the variables
+                nSumA = nSumR = nSumG = nSumB = nCount = 0;
+            }
+            else                 // 16 bits image.
+            {
+                unsigned short *org, *dst;
+
+                // first of all, we need to blur the vertical lines
+                for (n = -radius; !runningFlag() && (n <= radius); ++n)
+                {
+                    // if is inside...
+                    if (IsInside(width, height, w, h + n))
+                    {
+                        // we points to the pixel
+                        j = i + n * 4 * width;
+
+                        // finally, we sum the pixels using a method similar to assigntables
+                        org = &pBlur16[j];
+                        nSumA += arrMult[n + radius][org[3]];
+                        nSumR += arrMult[n + radius][org[2]];
+                        nSumG += arrMult[n + radius][org[1]];
+                        nSumB += arrMult[n + radius][org[0]];
+
+                        // we need to add to the counter, the kernel value
+                        nCount += Kernel[n + radius];
+                    }
+                }
+
+                if (nCount == 0) nCount = 1;
+
+                // To preserve Alpha channel.
+                memcpy (&pOutBits16[i], &data16[i], 8);
+
+                // now, we return to bits the vertical blur values
+                dst    = &pOutBits16[i];
+                dst[3] = (unsigned short)CLAMP (nSumA / nCount, 0, 65535);
+                dst[2] = (unsigned short)CLAMP (nSumR / nCount, 0, 65535);
+                dst[1] = (unsigned short)CLAMP (nSumG / nCount, 0, 65535);
+                dst[0] = (unsigned short)CLAMP (nSumB / nCount, 0, 65535);
+
+                // ok, now we reinitialize the variables
+                nSumA = nSumR = nSumG = nSumB = nCount = 0;
+            }
+        }
+
+        progress = (int) (50.0 + ((double)w * 50.0) / width);
+        if ( progress%5 == 0 )
+            postProgress( progress );
+    }
+
+    // now, we must free memory
+    Free2DArray (arrMult, nKernelWidth);
+    delete [] pBlur;
+    delete [] Kernel;
+}
+
+
 }  // namespace Digikam
--- trunk/extragear/graphics/digikam/libs/dimg/filters/fx/blurfilter.h #1196145:1196146
@@ -50,8 +50,42 @@
 private:
 
     void filterImage();
-    void gaussianBlurImage(uchar* data, int width, int height, bool sixteenBit, double radius);
+    void cimgBlurImage(uchar* data, int width, int height, bool sixteenBit, double radius);
+    void gaussianBlurImage(uchar* data, int width, int height, bool sixteenBit, int radius);
 
+    // function to allocate a 2d array
+    int** Alloc2DArray (int Columns, int Rows)
+    {
+        // First, we declare our future 2d array to be returned
+        int** lpcArray = 0L;
+
+        // Now, we alloc the main pointer with Columns
+        lpcArray = new int*[Columns];
+
+        for (int i = 0; i < Columns; ++i)
+            lpcArray[i] = new int[Rows];
+
+        return (lpcArray);
+    };
+
+    // Function to deallocates the 2d array previously created
+    void Free2DArray (int** lpcArray, int Columns)
+    {
+        // loop to deallocate the columns
+        for (int i = 0; i < Columns; ++i)
+            delete [] lpcArray[i];
+
+        // now, we delete the main pointer
+        delete [] lpcArray;
+    };
+
+    inline bool IsInside (int Width, int Height, int X, int Y)
+    {
+        bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true);
+        bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true);
+        return (bIsWOk && bIsHOk);
+    };
+
 private:
 
     double m_radius;



More information about the Digikam-devel mailing list