Faster Image Processing with OpenMP
by Henry A. Gabb and Bill Magro 


Listing One

void RadialBlur(void* data, int32 dataRowBytes, void* mask, int32 maskRowBytes, Rect* tileRect)
{
   uint8* pixel = (uint8*)data;   // Points to top left pixel of the image
   uint8* maskPixel = (uint8*)mask;
   uint16 rectHeight = (uint16)(tileRect->bottom - tileRect->top);
   uint16 rectWidth = (uint16)(tileRect->right - tileRect->left);
   // Variables for radial blur
   uint32 arc;       // Accumulate values on blur arc
   int n, step;      // Number of pixels on blur arc and increment
   int count;        // Number of arc pixels within rectangle
   float offset;     // Angular offset from blur pixel
   float theta;      // Angular increment of arc
   float angle;      // Angular sweep from rectangle center to blur pixel
   int R;            // Distance from rectangle center to rectangle corner
   int xr, yr, r;    // Distance from rectangle center to blur pixel
   int16 w, h;       // Coordinates of pixel at rectangle center
   float *ct, *st;   // Cosine and sine tables
   float xx, yy;     // Real coordinates of arc pixel
   int i;
   uint32 pixelOffset;
   const double PI = 3.141592654;
   Rect* filterRect = &gFilterRecord->filterRect;
   PSImagePlane plane;
   // Used to determine the addresses of pixels on blur arc
   plane.data = &gFilterRecord->inData;
   plane.bounds.top = filterRect->top;
   plane.bounds.bottom = filterRect->bottom;
   plane.bounds.left = filterRect->left;
   plane.bounds.right = filterRect->right;
   plane.rowBytes = gFilterRecord->outRowBytes;
   plane.colBytes = gFilterRecord->outColumnBytes;
   // Initialize radial blur variables
   // Find rectangle center (w,h)
   w = gFilterRecord->imageSize.h / 2;
   h = gFilterRecord->imageSize.v / 2;
   R = sqrt (w * w + h * h);
   angle = (float)gParams->angle / 180.0 * PI;   // Convert to radians
   n = 4 * angle * sqrt(R) + 2;
   theta = angle / ((float)(n - 1));
   // Setup cosine and sine tables
   if (((ct = (float *) malloc (n * sizeof(float))) == NULL ) ||
      ((st = (float *) malloc (n * sizeof(float))) == NULL ))
   {
      *gResult = memFullErr;
      return;
   }
   offset = theta * (n - 1) / 2;
   for (i = 0; i < n; ++i)
   {
      // Build sine and cosine tables
      ct[i] = cos(theta * i - offset);
      st[i] = sin(theta * i - offset);
   }
   // Loop over pixels in the image
   for(uint16 pixelY = 0; pixelY < rectHeight; pixelY++)
   {
      for(uint16 pixelX = 0; pixelX < rectWidth; pixelX++)
      {
         bool leaveItAlone = false;
         if (maskPixel != NULL && !(*maskPixel) && !gParams->ignoreSelection)
            leaveItAlone = true;
         if (!leaveItAlone)
         {
            // Find (x,y) coordinates of pixels on arc
            xr = pixelX - w;
            yr = pixelY - h;
            r = sqrt (xr * xr + yr * yr);
            if (r == 0)
               step = 1;
            else if ((step = R / r) == 0)
               step = 1;
            else if (step > (n - 1))
               step = n - 1;
            for (i = 0, count = 0, arc = 0; i < n; i += step)
            {
               xx = w + (float)xr * ct[i] - (float)yr * st[i];
               yy = h + (float)xr * st[i] + (float)yr * ct[i];
               if ((yy >= filterRect->bottom) || (yy < filterRect->top) ||
                   (xx < filterRect->left) || (xx >= filterRect->right))
                       continue;   // (x,y) outside rectangle
               ++count;
               // Convert (x,y) coordinate to pixel address
               pixelOffset = ((int)xx * gFilterRecord->outColumnBytes) +
                             ((int)yy * gFilterRecord->outRowBytes);
               arc += *((uint8 *)gFilterRecord->inData + pixelOffset);
            }
            if (count != 0)
               *pixel = (uint8)(arc / count);
         }
         pixel++;
         if (maskPixel != NULL)
            maskPixel++;
      }
      pixel += (dataRowBytes - rectWidth);
      if (maskPixel != NULL)
         maskPixel += (maskRowBytes - rectWidth);
   }
   // Clean-up sine and cosine tables
   free(ct);
   free(st);
}


Listing Two

#pragma omp parallel for schedule(dynamic) \
            private(pixelY, pixelX, pixelOffset, arcPixelOffset, \
                    i, count, arc, xx, yy, step, x, y, xr, yr, r)
   for (pixelY = 0; pixelY < rectHeight; pixelY++)
   {
      for (pixelX = 0; pixelX < rectWidth; pixelX++)
      {
         // Find (x,y) coordinates of current pixel
         x = gFilterRecord->inRect.left + pixelX;
         y = gFilterRecord->inRect.top + pixelY;

         pixelOffset = (x * gFilterRecord->outColumnBytes) +
                       (y * gFilterRecord->outRowBytes);
         bool leaveItAlone = false;
         if (maskPixel != NULL && !gParams->ignoreSelection &&
             !(*(maskPixel + pixelOffset)))
                leaveItAlone = true;
         if (!leaveItAlone)
         {
            xr = x - w;
            yr = y - h;
            r = sqrt (xr * xr + yr * yr);
            if (r == 0)
               step = 1;
            else if ((step = R / r) == 0)
               step = 1;
            else if (step > (n - 1))
               step = n - 1;
            for (i = 0, count = 0, arc = 0; i < n; i += step)
            {
               xx = w + (float)xr * ct[i] - (float)yr * st[i];
               yy = h + (float)xr * st[i] + (float)yr * ct[i];
               if ((yy >= filterRect->bottom) || (yy < filterRect->top) ||
                   (xx < filterRect->left) || (xx >= filterRect->right))
                       continue;   // (x,y) outside rectangle
               ++count;
               // Convert (x,y) coordinate to pixel address
               arcPixelOffset = ((int)xx * gFilterRecord->outColumnBytes) +
                                ((int)yy * gFilterRecord->outRowBytes);
               arc += *((uint8 *)gFilterRecord->inData + arcPixelOffset);
            }
            if (count != 0)
               *(pixel + pixelOffset) = (uint8)(arc / count);
         }
      }
   }

