...
diff --git a/MagickCore/effect.c b/MagickCore/effect.c
index 49a9840..adfd151 100644
--- a/MagickCore/effect.c
+++ b/MagickCore/effect.c
@@ -861,6 +861,44 @@
     PerceptibleReciprocal(Magick2PI*sigma*sigma));
 }
 
+static double **DestroyBilateralThreadSet(double **weights)
+{
+  register ssize_t
+    i;
+
+  assert(weights != (double **) NULL);
+  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
+    if (weights[i] != (double *) NULL)
+      weights[i]=(double *) RelinquishMagickMemory(weights[i]);
+  weights=(double **) RelinquishMagickMemory(weights);
+  return(weights);
+}
+
+static double **AcquireBilateralThreadSet(const size_t width)
+{
+  double
+    **weights;
+
+  register ssize_t
+    i;
+
+  size_t
+    number_threads;
+
+  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
+  weights=(double **) AcquireQuantumMemory(number_threads,sizeof(*weights));
+  if (weights == (double **) NULL)
+    return((double **) NULL);
+  (void) memset(weights,0,number_threads*sizeof(*weights));
+  for (i=0; i < (ssize_t) number_threads; i++)
+  {
+    weights[i]=(double *) AcquireQuantumMemory(width,width*sizeof(**weights));
+    if (weights[i] == (double *) NULL)
+      return(DestroyBilateralThreadSet(weights));
+  }
+  return(weights);
+}
+
 MagickExport Image *BilateralBlurImage(const Image *image,const double radius,
   const double sigma,const double intensity_sigma,const double spatial_sigma,
   ExceptionInfo *exception)
@@ -871,6 +909,9 @@
     *blur_view,
     *image_view;
 
+  double
+    **weights;
+
   Image
     *blur_image;
 
@@ -901,13 +942,18 @@
       blur_image=DestroyImage(blur_image);
       return((Image *) NULL);
     }
+  width=GetOptimalKernelWidth2D(radius,sigma);
+  weights=AcquireBilateralThreadSet(width);
+  if (weights == (double **) NULL)
+    {
+      blur_image=DestroyImage(blur_image);
+      ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
+    }
   /*
     Bilateral blur image.
   */
   status=MagickTrue;
   progress=0;
-  width=GetOptimalKernelWidth2D(radius,sigma);
-printf("%d\n",width);
   mid=(ssize_t) width/2L;
   image_view=AcquireVirtualCacheView(image,exception);
   blur_view=AcquireAuthenticCacheView(blur_image,exception);
@@ -917,6 +963,9 @@
 #endif
   for (y=0; y < (ssize_t) blur_image->rows; y++)
   {
+    const int
+      id = GetOpenMPThreadId();
+
     register Quantum
       *magick_restrict q;
 
@@ -934,25 +983,46 @@
       }
     for (x=0; x < (ssize_t) blur_image->columns; x++)
     {
+      double
+        gamma,
+        pixel;
+
       register const Quantum
-        *magick_restrict n,
+        *magick_restrict r,
         *magick_restrict p;
 
       register ssize_t
-        i;
+        i,
+        u;
 
+      ssize_t
+        n,
+        v;
+
+      /*
+        Tonal weighting preserves edges while smoothing in the flat regions.
+      */
       p=GetCacheViewVirtualPixels(image_view,x-mid,y-mid,width,width,exception);
       if (p == (const Quantum *) NULL)
         break;
       p+=(ssize_t) GetPixelChannels(image)*width*mid+GetPixelChannels(image)*
         mid;
+      n=0;
+      for (v=0; v < (ssize_t) width; v++)
+      {
+        for (u=0; u < (ssize_t) width; u++)
+        {
+          r=p+(ssize_t) GetPixelChannels(image)*width*(mid-v)+
+            GetPixelChannels(image)*(mid-u);
+          weights[id][n]=BlurGaussian(ScaleQuantumToChar(
+            GetPixelIntensity(image,r))-(double) ScaleQuantumToChar(
+            GetPixelIntensity(image,p)),intensity_sigma)*BlurGaussian(
+            BlurDistance(x,y,x+u-mid,y+v-mid),spatial_sigma);
+          n++;
+        }
+      }
       for (i=0; i < (ssize_t) GetPixelChannels(blur_image); i++)
       {
-        double
-          gamma,
-          pixel,
-          weight;
-
         PixelChannel
           channel;
 
@@ -960,12 +1030,6 @@
           blur_traits,
           traits;
 
-        register ssize_t
-          u;
-
-        ssize_t
-          v;
-
         channel=GetPixelChannelChannel(image,i);
         traits=GetPixelChannelTraits(image,channel);
         blur_traits=GetPixelChannelTraits(blur_image,channel);
@@ -979,6 +1043,7 @@
           }
         pixel=0.0;
         gamma=0.0;
+        n=0;
         if ((blur_traits & BlendPixelTrait) == 0)
           {
             /*
@@ -988,13 +1053,11 @@
             {
               for (u=0; u < (ssize_t) width; u++)
               {
-                n=p+(ssize_t) GetPixelChannels(image)*width*(mid-v)+
+                r=p+(ssize_t) GetPixelChannels(image)*width*(mid-v)+
                   GetPixelChannels(image)*(mid-u);
-                weight=BlurGaussian(ScaleQuantumToChar(n[i])-(ssize_t)
-                  ScaleQuantumToChar(p[i]),intensity_sigma)*BlurGaussian(
-                  BlurDistance(x,y,x+u-mid,y+v-mid),spatial_sigma);
-                pixel+=weight*n[i];
-                gamma+=weight;
+                pixel+=weights[id][n]*r[i];
+                gamma+=weights[id][n];
+                n++;
               }
             }
             SetPixelChannel(blur_image,channel,ClampToQuantum(
@@ -1012,15 +1075,13 @@
               alpha,
               beta;
 
-            n=p+(ssize_t) GetPixelChannels(image)*width*(mid-v)+
+            r=p+(ssize_t) GetPixelChannels(image)*width*(mid-v)+
               GetPixelChannels(image)*(mid-u);
             alpha=(double) (QuantumScale*GetPixelAlpha(image,p));
-            beta=(double) (QuantumScale*GetPixelAlpha(image,n));
-            weight=BlurGaussian(ScaleQuantumToChar(n[i])-(ssize_t)
-              ScaleQuantumToChar(p[i]),intensity_sigma)*BlurGaussian(
-              BlurDistance(x,y,x+u-mid,y+v-mid),spatial_sigma);
-            pixel+=weight*n[i];
-            gamma+=weight*alpha*beta;
+            beta=(double) (QuantumScale*GetPixelAlpha(image,r));
+            pixel+=weights[id][n]*r[i];
+            gamma+=weights[id][n]*alpha*beta;
+            n++;
           }
         }
         SetPixelChannel(blur_image,channel,ClampToQuantum(
@@ -1048,6 +1109,7 @@
   blur_image->type=image->type;
   blur_view=DestroyCacheView(blur_view);
   image_view=DestroyCacheView(image_view);
+  weights=DestroyBilateralThreadSet(weights);
   if (status == MagickFalse)
     blur_image=DestroyImage(blur_image);
   return(blur_image);